PluginProbe
Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More / 2.3.1
Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More v2.3.1
2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.2 2.2.1 2.2.0 2.1.2 2.1.1 trunk 0.0.1 0.0.2 0.0.3 0.0.4 0.0.5 0.0.6 0.0.7 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 All 66 releases
better-payment / includes / AI / Services / BriefWriter.php

BriefWriter.php in Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More 2.3.1, at includes/AI/Services/BriefWriter.php

118 lines 4.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Better_Payment\Lite\AI\Services;
4
5 if ( ! defined( 'ABSPATH' ) ) {
6 exit;
7 }
8
9 /**
10 * Campaign brief writer / refiner — the wizard's pre-generation step.
11 *
12 * Runs {@see AIService} in the text-only 'brief' mode. Given the brief the Smart
13 * Prompt Wizard assembled (and, optionally, a plain-language instruction), it
14 * returns an improved brief *as text* — nothing is applied to any campaign. The
15 * user reviews and edits the result, then hands it to the 'generate' turn.
16 *
17 * This class exists so the wizard can offer "Refine with AI" without the generate
18 * pipeline: no operations, no layout, no guards to run — just prose in, prose out.
19 * The one guarantee it adds on top of the raw turn is that the reply is cleaned of
20 * any machine wrapping (stray quotes, code fences) before it reaches the editable
21 * brief box, since the model is told to emit bare prose but a prompt is a request.
22 *
23 * @see \Better_Payment\Lite\AI\Prompt\Templates (brief.php) for the hard rules —
24 * chiefly that it never invents or alters a goal amount or an end date, which
25 * are owned by the wizard's structured answers and enforced at generation.
26 */
27 class BriefWriter {
28
29 /**
30 * Improve a campaign brief.
31 *
32 * @param string $brief The current brief text (the wizard's assembled
33 * brief, or a previously refined one).
34 * @param string $instruction Optional plain-language "make it more…" request.
35 * '' means a general polish.
36 * @return array|\WP_Error { brief: string, usage: array }
37 */
38 public static function write( string $brief, string $instruction = '' ) {
39 $brief = trim( $brief );
40 if ( '' === $brief ) {
41 return new \WP_Error(
42 'ai_brief_missing',
43 __( 'There is no brief to refine yet.', 'better-payment' ),
44 [ 'status' => 400 ]
45 );
46 }
47
48 $result = AIService::run( 'brief', self::compose_message( $brief, trim( $instruction ) ) );
49 if ( is_wp_error( $result ) ) {
50 return $result;
51 }
52
53 $text = self::clean( (string) ( $result['assistant_message'] ?? '' ) );
54 if ( '' === $text ) {
55 return new \WP_Error(
56 'ai_brief_empty',
57 __( 'The assistant did not return an improved brief. Please try again.', 'better-payment' ),
58 [ 'status' => 502 ]
59 );
60 }
61
62 return [
63 'brief' => $text,
64 'usage' => $result['usage'] ?? [],
65 ];
66 }
67
68 /**
69 * Build the user message: the current brief, plus the improvement instruction
70 * when there is one. Labelled plainly so the model knows which part is the
71 * brief to rewrite and which is the direction to follow.
72 *
73 * @param string $brief
74 * @param string $instruction
75 * @return string
76 */
77 private static function compose_message( string $brief, string $instruction ): string {
78 if ( '' === $instruction ) {
79 return "Current brief:\n\n" . $brief
80 . "\n\nRewrite this brief so it is more vivid, specific and complete, following the rules above.";
81 }
82
83 return "Current brief:\n\n" . $brief
84 . "\n\nImprove the brief following this instruction: " . $instruction;
85 }
86
87 /**
88 * Strip machine wrapping from a reply meant to be bare prose.
89 *
90 * The model is told to return the brief and nothing else, but occasionally
91 * wraps it in a code fence or surrounding quotes. Remove those so they don't
92 * land in the user's editable brief box. This unwraps structure; it does not
93 * rewrite the writing.
94 *
95 * @param string $text
96 * @return string
97 */
98 private static function clean( string $text ): string {
99 $text = trim( $text );
100
101 // A fully fenced reply → keep only the fence's contents.
102 if ( preg_match( '/^```[a-z]*\s*\n(.*?)\n?```$/is', $text, $matches ) ) {
103 $text = trim( $matches[1] );
104 }
105
106 // Surrounding matched quotes the model sometimes adds around the whole brief.
107 if ( strlen( $text ) >= 2 ) {
108 $first = $text[0];
109 $last = $text[ strlen( $text ) - 1 ];
110 if ( ( '"' === $first && '"' === $last ) || ( "'" === $first && "'" === $last ) ) {
111 $text = trim( substr( $text, 1, -1 ) );
112 }
113 }
114
115 return $text;
116 }
117 }
118