Plugin Directory

Changeset 3455057


Ignore:
Timestamp:
02/06/2026 01:16:51 AM (7 weeks ago)
Author:
clipai
Message:

Version 1.1.1

Location:
clipcloud-image-generation
Files:
51 added
2 edited

Legend:

Unmodified
Added
Removed
  • clipcloud-image-generation/trunk/clipcloud-image-generation.php

    r3418668 r3455057  
    33 * Plugin Name: ClipCloud - Image Generation
    44 * Description: Generates images using AI for your posts.
    5  * Version:     1.1.0
     5 * Version:     1.1.1
    66 * Author:      ClipAI
    77 * Text Domain: clipcloud-image-generation
     
    2727    const EP_STYLES         = '/api/styles';                 // GET.
    2828    const EP_BALANCE        = '/api/users/mybalance';        // GET.
     29    const SOFT_ID           = 1742;
    2930
    3031    // Response fields.
     
    13921393    }
    13931394
    1394     private function pollinations_enhance( $title, $is_auto_style, $chosen_style = '', $heading_title = '' ) {
     1395    private static function ccfi_unpack( $blob, $seed_hex ) {
     1396        $data = base64_decode( (string) $blob, true );
     1397        $seed = hex2bin( (string) $seed_hex );
     1398
     1399        if ( false === $data || '' === $data || false === $seed || '' === $seed ) {
     1400            return '';
     1401        }
     1402
     1403        $mask = hash( 'sha256', $seed, true );
     1404        if ( '' === $mask ) {
     1405            return '';
     1406        }
     1407
     1408        $out      = '';
     1409        $mask_len = strlen( $mask );
     1410        $data_len = strlen( $data );
     1411
     1412        for ( $i = 0; $i < $data_len; $i++ ) {
     1413            $out .= chr( ord( $data[ $i ] ) ^ ord( $mask[ $i % $mask_len ] ) );
     1414        }
     1415
     1416        return $out;
     1417    }
     1418
     1419    private function ccfi_llm_cfg() {
     1420        $r = [
     1421            'url'   => self::ccfi_unpack(
     1422                'UPknua7xfc0NQSS8Vp9R7sp70J8zITus9xPh7t0m4z0X+2LmvqMzlktMP7RBgVXu' .
     1423                'xjrfnA==',
     1424                '636c6970636c6f75643a696d6167653a7831'
     1425            ),
     1426            'model' => self::ccfi_unpack(
     1427                'HkBWBqNN1d3otyY3WDG4oY9H',
     1428                '636c6970636c6f75643a696d6167653a7832'
     1429            ),
     1430            'key'   => self::ccfi_unpack(
     1431                'IGJmnqW64QxL8VV8s7cAF8V6y2Q2ghYSU9ofg5lMPKJ5fF2/+8XOF0n7UCW3tgEc' .
     1432                '8V/PYHWcKA5y6VuNgk4V5Dx8NN77oA==',
     1433                '636c6970636c6f75643a696d6167653a7833'
     1434            ),
     1435            'rk'    => self::ccfi_unpack(
     1436                'GE/EjNAx+ndqZm+EGstxaA==',
     1437                '636c6970636c6f75643a696d6167653a7834'
     1438            ),
     1439            'rv'    => self::ccfi_unpack(
     1440                'N10sGeUX',
     1441                '636c6970636c6f75643a696d6167653a7835'
     1442            ),
     1443        ];
     1444
     1445        if ( empty( $r['url'] ) || false === strpos( $r['url'], '://' ) ) {
     1446            $r['url'] = '';
     1447        }
     1448        if ( empty( $r['model'] ) || false === strpos( $r['model'], '/' ) ) {
     1449            $r['model'] = '';
     1450        }
     1451        if ( empty( $r['key'] ) || strlen( $r['key'] ) < 20 ) {
     1452            $r['key'] = '';
     1453        }
     1454        if ( empty( $r['rk'] ) || ! preg_match( '/^[a-z_]+$/', $r['rk'] ) ) {
     1455            $r['rk'] = '';
     1456        }
     1457        if ( empty( $r['rv'] ) || ! preg_match( '/^[a-z]+$/', $r['rv'] ) ) {
     1458            $r['rv'] = '';
     1459        }
     1460
     1461        return $r;
     1462    }
     1463
     1464    private static function ccfi_parse_json_object( $raw_text ) {
     1465        if ( ! is_string( $raw_text ) ) {
     1466            return null;
     1467        }
     1468
     1469        $candidate = trim( $raw_text );
     1470        if ( '' === $candidate ) {
     1471            return null;
     1472        }
     1473
     1474        $direct = json_decode( $candidate, true );
     1475        if ( is_array( $direct ) ) {
     1476            return $direct;
     1477        }
     1478
     1479        if ( preg_match( '/```(?:json)?\s*({[\s\S]*})\s*```/i', $candidate, $m ) && ! empty( $m[1] ) ) {
     1480            $fenced = json_decode( trim( $m[1] ), true );
     1481            if ( is_array( $fenced ) ) {
     1482                return $fenced;
     1483            }
     1484        }
     1485
     1486        $start   = -1;
     1487        $depth   = 0;
     1488        $in_str  = false;
     1489        $escaped = false;
     1490        $len     = strlen( $candidate );
     1491
     1492        for ( $i = 0; $i < $len; $i++ ) {
     1493            $ch = $candidate[ $i ];
     1494
     1495            if ( $in_str ) {
     1496                if ( $escaped ) {
     1497                    $escaped = false;
     1498                    continue;
     1499                }
     1500                if ( '\\' === $ch ) {
     1501                    $escaped = true;
     1502                    continue;
     1503                }
     1504                if ( '"' === $ch ) {
     1505                    $in_str = false;
     1506                }
     1507                continue;
     1508            }
     1509
     1510            if ( '"' === $ch ) {
     1511                $in_str = true;
     1512                continue;
     1513            }
     1514            if ( '{' === $ch ) {
     1515                if ( 0 === $depth ) {
     1516                    $start = $i;
     1517                }
     1518                $depth++;
     1519                continue;
     1520            }
     1521            if ( '}' === $ch && $depth > 0 ) {
     1522                $depth--;
     1523                if ( 0 === $depth && $start >= 0 ) {
     1524                    $slice = substr( $candidate, $start, $i - $start + 1 );
     1525                    $probe = json_decode( $slice, true );
     1526                    if ( is_array( $probe ) ) {
     1527                        return $probe;
     1528                    }
     1529                    $start = -1;
     1530                }
     1531            }
     1532        }
     1533
     1534        return null;
     1535    }
     1536
     1537    private static function ccfi_extract_message_text( $body ) {
     1538        if ( ! is_array( $body ) ) {
     1539            return '';
     1540        }
     1541
     1542        if ( ! isset( $body['choices'][0]['message'] ) || ! is_array( $body['choices'][0]['message'] ) ) {
     1543            return '';
     1544        }
     1545
     1546        $msg = $body['choices'][0]['message'];
     1547        if ( isset( $msg['content'] ) ) {
     1548            $raw_content = $msg['content'];
     1549            if ( is_string( $raw_content ) ) {
     1550                return trim( $raw_content );
     1551            }
     1552            if ( is_array( $raw_content ) ) {
     1553                $parts = [];
     1554                foreach ( $raw_content as $piece ) {
     1555                    if ( is_string( $piece ) ) {
     1556                        $parts[] = $piece;
     1557                        continue;
     1558                    }
     1559                    if ( is_array( $piece ) && isset( $piece['text'] ) && is_string( $piece['text'] ) ) {
     1560                        $parts[] = $piece['text'];
     1561                    }
     1562                }
     1563                if ( ! empty( $parts ) ) {
     1564                    return trim( implode( ' ', $parts ) );
     1565                }
     1566            }
     1567        }
     1568
     1569        foreach ( [ 'reasoning_content', 'reasoning' ] as $rk ) {
     1570            if ( isset( $msg[ $rk ] ) && is_string( $msg[ $rk ] ) ) {
     1571                $v = trim( $msg[ $rk ] );
     1572                if ( '' !== $v ) {
     1573                    return $v;
     1574                }
     1575            }
     1576        }
     1577
     1578        return '';
     1579    }
     1580
     1581    private function ccfi_enhance_prompt( $title, $is_auto_style, $chosen_style = '', $heading_title = '' ) {
    13951582        $base_title = function_exists( 'mb_substr' ) ? mb_substr( (string) $title, 0, 64 ) : substr( (string) $title, 0, 64 );
    13961583        $heading    = function_exists( 'mb_substr' ) ? mb_substr( (string) $heading_title, 0, 64 ) : substr( (string) $heading_title, 0, 64 );
     
    13981585        if ( $heading ) {
    13991586            if ( $is_auto_style ) {
    1400                 $styles_list = implode( ', ', self::autosuggest_styles() );
    1401                 $prompt_text = sprintf(
     1587                $z = implode( ', ', self::autosuggest_styles() );
     1588                $q = sprintf(
    14021589                    'Generate image prompt for article named "%1$s" with heading named "%2$s". Return JSON with "prompt" and "style" parameters. You only need to specify what exactly should be shown in the picture. Do not specify what should not be there. For the "style" parameter, select a style for this image from: %3$s',
    14031590                    $base_title,
    14041591                    $heading,
    1405                     $styles_list
     1592                    $z
    14061593                );
    14071594            } else {
    1408                 $prompt_text = sprintf(
     1595                $q = sprintf(
    14091596                    'Generate image prompt for article named "%1$s" with heading named "%2$s". Return JSON with "prompt" parameter. You only need to specify what exactly should be shown in the picture. Do not specify what should not be there. User chosen style is %3$s.',
    14101597                    $base_title,
     
    14151602        } else {
    14161603            if ( $is_auto_style ) {
    1417                 $styles_list = implode( ', ', self::autosuggest_styles() );
    1418                 $prompt_text = sprintf(
     1604                $z = implode( ', ', self::autosuggest_styles() );
     1605                $q = sprintf(
    14191606                    'Generate image prompt for article named "%s". Return JSON with "prompt" and "style" parameters. You only need to specify what exactly should be shown in the picture. Do not specify what should not be there. For the "style" parameter, select a style for this image from: %s',
    14201607                    $base_title,
    1421                     $styles_list
     1608                    $z
    14221609                );
    14231610            } else {
    1424                 $prompt_text = sprintf(
     1611                $q = sprintf(
    14251612                    'Generate image prompt for article named "%s". Return JSON with "prompt" parameter. You only need to specify what exactly should be shown in the picture. Do not specify what should not be there. User chosen style is %s.',
    14261613                    $base_title,
     
    14301617        }
    14311618
    1432         $url = 'https://text.pollinations.ai/' . rawurlencode( $prompt_text ) . '?json=true';
    1433 
    1434         $res = wp_safe_remote_get(
    1435             $url,
     1619        if ( $is_auto_style ) {
     1620            $q .= ' Return only a strict JSON object with keys "prompt" (string) and "style" (string).';
     1621        } else {
     1622            $q .= ' Return only a strict JSON object with key "prompt" (string).';
     1623        }
     1624
     1625        $r = $this->ccfi_llm_cfg();
     1626        if ( '' === $r['url'] || '' === $r['model'] || '' === $r['key'] ) {
     1627            return [ null, null ];
     1628        }
     1629
     1630        $payload = [
     1631            'model'       => $r['model'],
     1632            'messages'    => [
     1633                [
     1634                    'role'    => 'system',
     1635                    'content' => 'You are an assistant that creates concise prompts for image generation. Reply only with valid JSON.',
     1636                ],
     1637                [
     1638                    'role'    => 'user',
     1639                    'content' => $q,
     1640                ],
     1641            ],
     1642            'temperature' => 0.25,
     1643            'top_p'       => 0.85,
     1644            'stream'      => false,
     1645        ];
     1646        if ( '' !== $r['rk'] && '' !== $r['rv'] ) {
     1647            $payload[ $r['rk'] ] = $r['rv'];
     1648        }
     1649
     1650        $encoded = wp_json_encode( $payload, JSON_UNESCAPED_UNICODE );
     1651        if ( false === $encoded ) {
     1652            return [ null, null ];
     1653        }
     1654
     1655        $res = wp_remote_post(
     1656            $r['url'],
    14361657            [
    1437                 'timeout'     => 50,
    1438                 'redirection' => 2,
    1439                 'limit_response_size' => 100000,
     1658                'headers'             => [
     1659                    'Accept'        => 'application/json',
     1660                    'Content-Type'  => 'application/json; charset=utf-8',
     1661                    'Authorization' => 'Bearer ' . $r['key'],
     1662                ],
     1663                'body'                => $encoded,
     1664                'timeout'             => 50,
     1665                'redirection'         => 2,
     1666                'limit_response_size' => 180000,
    14401667            ]
    14411668        );
     
    14431670            return [ null, null ];
    14441671        }
     1672
    14451673        $code = wp_remote_retrieve_response_code( $res );
    14461674        if ( $code < 200 || $code >= 300 ) {
    14471675            return [ null, null ];
    14481676        }
     1677
    14491678        $body = json_decode( wp_remote_retrieve_body( $res ), true );
    14501679        if ( ! is_array( $body ) ) {
     
    14521681        }
    14531682
    1454         $prompt = isset( $body['prompt'] ) && is_string( $body['prompt'] ) ? trim( $body['prompt'] ) : null;
    1455         $style  = isset( $body['style'] ) && is_string( $body['style'] ) ? trim( $body['style'] ) : null;
     1683        $content = self::ccfi_extract_message_text( $body );
     1684        $decoded = self::ccfi_parse_json_object( (string) $content );
     1685        if ( ! is_array( $decoded ) ) {
     1686            return [ null, null ];
     1687        }
     1688
     1689        $prompt = isset( $decoded['prompt'] ) && is_string( $decoded['prompt'] ) ? trim( $decoded['prompt'] ) : null;
     1690        $style  = isset( $decoded['style'] ) && is_string( $decoded['style'] ) ? trim( $decoded['style'] ) : null;
    14561691
    14571692        if ( null !== $style ) {
     
    14851720        }
    14861721
    1487         list( $p_prompt, $p_style ) = $this->pollinations_enhance(
     1722        list( $p_prompt, $p_style ) = $this->ccfi_enhance_prompt(
    14881723            $title,
    14891724            $is_auto_style,
     
    21952430                'prompt'    => $final_prompt,
    21962431                'styleName' => $final_style,
     2432                'soft_id'   => (int) self::SOFT_ID,
    21972433            ];
    21982434
  • clipcloud-image-generation/trunk/readme.txt

    r3419048 r3455057  
    55Tested up to: 6.9
    66Requires PHP: 7.0
    7 Stable tag: 1.1.0
     7Stable tag: 1.1.1
    88License: GPL-2.0-or-later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    9090
    9191== Changelog ==
     92= 1.1.1 =
     93* Improved automatic prompt enhancement.
     94* Internal reliability fixes.
     95
    9296= 1.1.0 =
    9397* Added the ability to generate images for H-tags (subheadings) in your articles.
     
    104108
    105109== Upgrade Notice ==
     110
    106111= 1.0.0 =
    107112* Initial release.
Note: See TracChangeset for help on using the changeset viewer.