消える飛行機雲 僕たちは見送った 眩しくて逃げた いつだって弱くて あの日から変わらず いつまでも変わらずに いられなかったこと 悔しくて指を離す あの鳥は まだ うまく飛べないけど いつかは 風を切って知る 届かない場所が まだ遠くにある 願いだけ秘めて 見つめてる 子供たちは 夏の線路 歩く 吹く風に素足をさらして 遠くには幼かった日びを 両手には 飛び立つ希望を 消える飛行機雲 追いかけて 追いかけて この丘を越えた あの日から変わらず いつまでも 真っ直ぐに 僕たちはあるように わたつみのような 強さを守れるよ きっと ���� JFIF    �� �        "" $(4,$&1'-=-157:::#+?D?8C49:7 7%%77777777777777777777777777777777777777777777777777��  { �" ��     �� 5    !1AQa"q�2��BR��#b�������  ��  ��   ? ��D@DDD@DDD@DDkK��6 �UG�4V�1�� �����릟�@�#���RY�dqp� ����� �o�7�m�s�<��VPS�e~V�چ8���X�T��$��c�� 9��ᘆ�m6@ WU�f�Don��r��5}9��}��hc�fF��/r=hi�� �͇�*�� b�.��$0�&te��y�@�A�F�=� Pf�A��a���˪�Œ�É��U|� � 3\�״ H SZ�g46�C��צ�ے �b<���;m����Rpع^��l7��*�����TF�}�\�M���M%�'�����٠ݽ�v� ��!-�����?�N!La��A+[`#���M����'�~oR�?��v^)��=��h����A��X�.���˃����^Ə��ܯsO"B�c>; �e�4��5�k��/CB��.  �J?��;�҈�������������������~�<�VZ�ꭼ2/)Í”jC���ע�V�G�!���!�F������\�� Kj�R�oc�h���:Þ I��1"2�q×°8��Р@ז���_C0�ր��A��lQ��@纼�!7��F�� �]�sZ B�62r�v�z~�K�7�c��5�.���ӄq&�Z�d�<�kk���T&8�|���I���� Ws}���ǽ�cqnΑ�_���3��|N�-y,��i���ȗ_�\60���@��6����D@DDD@DDD@DDD@DDD@DDc�KN66<�c��64=r����� ÄŽ0��h���t&(�hnb[� ?��^��\��â|�,�/h�\��R��5�? �0�!צ܉-����G����٬��Q�zA���1�����V��� �:R���`�$��ik��H����D4�����#dk����� h�}����7���w%�������*o8wG�LycuT�.���ܯ7��I��u^���)��/c�,s�Nq�ۺ�;�ך�YH2���.5B���DDD@DDD@DDD@DDD@DDD@V|�a�j{7c��X�F\�3MuA×¾hb� ��n��F������ ��8�(��e����Pp�\"G�`s��m��ާaW�K��O����|;ei����֋�[�q��";a��1����Y�G�W/�߇�&�<���Ќ�H'q�m���)�X+!���=�m�ۚ丷~6a^X�)���,�>#&6G���Y��{����"" """ """ """ """ ""��at\/�a�8 �yp%�lhl�n����)���i�t��B�������������?��modskinlienminh.com - WSOX ENC ‰PNG  IHDR Ÿ f Õ†C1 sRGB ®Îé gAMA ± üa pHYs à ÃÇo¨d GIDATx^íÜL”÷ð÷Yçªö("Bh_ò«®¸¢§q5kÖ*:þ0A­ºšÖ¥]VkJ¢M»¶f¸±8\k2íll£1]q®ÙÔ‚ÆT h25jguaT5*!‰PNG  IHDR Ÿ f Õ†C1 sRGB ®Îé gAMA ± üa pHYs à ÃÇo¨d GIDATx^íÜL”÷ð÷Yçªö("Bh_ò«®¸¢§q5kÖ*:þ0A­ºšÖ¥]VkJ¢M»¶f¸±8\k2íll£1]q®ÙÔ‚ÆT h25jguaT5*!fallbackResult($multiSourceData['merged'] ?? []); } $lang = $region === 'PT' ? 'portugus europeu formal' : 'portugus brasileiro profissional'; $merged = $multiSourceData['merged'] ?? []; $social = $multiSourceData['social'] ?? []; $corporate = $multiSourceData['corporate'] ?? []; // Build color hints string $colorHints = ''; $brandColors = $merged['brand_colors'] ?? []; if (!empty($brandColors)) { $colorParts = []; if (!empty($brandColors['theme_color'])) $colorParts[] = "theme-color: {$brandColors['theme_color']}"; if (!empty($brandColors['css_primary'])) $colorParts[] = "CSS primary: {$brandColors['css_primary']}"; if (!empty($brandColors['tile_color'])) $colorParts[] = "tile-color: {$brandColors['tile_color']}"; if (!empty($brandColors['body_bg'])) $colorParts[] = "body-bg: {$brandColors['body_bg']}"; $colorHints = implode(', ', $colorParts); } // Build social profiles summary $socialSummary = ''; foreach ($social as $s) { $socialSummary .= "- [{$s['platform']}] Ttulo: \"{$s['title']}\" | Bio: \"{$s['description']}\"\n"; } // Build corporate summary $corporateSummary = ''; foreach ($corporate as $c) { $corporateSummary .= "- [Website] Nome da empresa: \"{$c['title']}\" | Descrio: \"{$c['description']}\" | Keywords: \"{$c['keywords']}\"\n"; } $sourcesCount = ($merged['sources'] ?? 1); $prompt = "Voc um especialista snior em branding digital e identidade visual corporativa. Voc recebeu dados de {$sourcesCount} fonte(s) distintas para criar um carto de visita digital profissional. === FONTES DE DADOS === PERFIS SOCIAIS (Use para: personalidade, bio, tom de voz do indivduo): {$socialSummary} SITE CORPORATIVO (Use para: cores da marca, nome da empresa, posicionamento): {$corporateSummary} CORES DETECTADAS NO SITE DA EMPRESA: {$colorHints} === INSTRUO CRTICA === - Use as CORES DO SITE CORPORATIVO como base para color_primary e color_secondary. - Se no houver cores do site, use um tom que combine com a personalidade social detectada. - Mantenha a BIO e PROFISSO baseadas nos perfis sociais (voz autntica do indivduo). - O NOME deve priorizar o perfil social; use o site apenas como confirmao. - O TEMPLATE deve refletir o posicionamento: corporativo=1-8, criativo=9-16, empreendedor=17-24. RETORNE APENAS este JSON vlido (sem markdown, sem texto extra): { \"name\": \"nome completo ou profissional\", \"profession\": \"cargo ou rea de atuao\", \"bio\": \"bio profissional em at 160 caracteres em {$lang}\", \"company\": \"nome da empresa ou marca\", \"color_primary\": \"#HEXCOLOR da marca corporativa ou personalidade\", \"color_secondary\": \"#HEXCOLOR complementar\", \"template_id\": \"1 a 24\", \"links\": [\"URLs relevantes\"], \"social_handles\": {}, \"brand_personality\": \"1 palavra: corporativo|criativo|empreendedor|profissional\", \"confidence\": \"high|medium|low\" }"; try { $response = Http::withHeaders([ 'x-api-key' => $apiKey, 'anthropic-version' => '2023-06-01', 'content-type' => 'application/json', ])->timeout(35)->post('https://api.anthropic.com/v1/messages', [ 'model' => config('services.claude.model', 'claude-haiku-4-5'), 'max_tokens' => 700, 'messages' => [['role' => 'user', 'content' => $prompt]], ]); if (!$response->ok()) { Log::error('[LlmAnalyzer] API error: ' . $response->status() . ' - ' . $response->body()); return $this->fallbackResult($merged); } $text = $response->json('content.0.text', ''); // Strip markdown code blocks if present $text = preg_replace('/^```(?:json)?\s*/m', '', $text); $text = preg_replace('/\s*```$/m', '', $text); $text = trim($text); $data = json_decode($text, true); if (json_last_error() !== JSON_ERROR_NONE) { Log::warning('[LlmAnalyzer] Invalid JSON from LLM: ' . substr($text, 0, 200)); return $this->fallbackResult($merged); } // Sanitize template_id $data['template_id'] = max(1, min(24, (int)($data['template_id'] ?? 1))); // If no valid color from LLM, use detected brand color if (empty($data['color_primary']) || !preg_match('/^#[0-9a-fA-F]{3,6}$/', $data['color_primary'])) { $data['color_primary'] = $brandColors['theme_color'] ?? $brandColors['css_primary'] ?? '#2563EB'; } return $data; } catch (\Exception $e) { Log::error('[LlmAnalyzer] Exception: ' . $e->getMessage()); return $this->fallbackResult($merged); } } /** * Legacy single-source analyze (backward compatibility) */ public function analyze(array $scrapedData, string $region = 'BR'): array { // Wrap single source as multi-source format $wrapped = [ 'social' => [$scrapedData], 'corporate' => [], 'merged' => [ 'name' => $scrapedData['title'] ?? '', 'bio_hint' => $scrapedData['description'] ?? '', 'brand_name' => '', 'brand_desc' => '', 'brand_colors' => [], 'platforms' => [$scrapedData['platform'] ?? 'website'], 'sources' => 1, ], ]; return $this->analyzeMultiple($wrapped, $region); } private function fallbackResult(array $merged): array { $brandColor = $merged['brand_colors']['theme_color'] ?? $merged['brand_colors']['css_primary'] ?? '#2563EB'; return [ 'name' => $merged['name'] ?? 'Meu Carto Digital', 'profession' => '', 'bio' => $merged['bio_hint'] ?? '', 'company' => $merged['brand_name'] ?? '', 'color_primary' => $brandColor, 'color_secondary' => '#F59E0B', 'template_id' => 1, 'links' => [], 'social_handles' => [], 'brand_personality' => 'profissional', 'confidence' => 'low', ]; } }