""" HTMLバリアント生成API 允E�EHTMLと変更点を受け取り、Eつの新しいHTMLを提案すめE """ import os from src.clients.llm_client import LLMClient import json import re from typing import List from pydantic import BaseModel, Field from datetime import datetime import pytz from src.utils.tracer import customtracer def _ask_raw_hf(messages, model, response_format=None): """Compatibility wrapper: routes OpenAI-style messages through HF LLMClient.""" from src.clients.llm_client import LLMClient import json as _json client = LLMClient() system_prompt = None user_text = "" images = [] for msg in messages: role = msg.get("role", "") c = msg.get("content", "") if role == "system": if isinstance(c, str): system_prompt = c elif role == "user": if isinstance(c, str): user_text = c elif isinstance(c, list): for part in c: if isinstance(part, dict): if part.get("type") == "text": user_text += part.get("text", "") elif part.get("type") == "image_url": url = part.get("image_url", {}).get("url", "") if url.startswith("data:"): images.append(url.split(",", 1)[1] if "," in url else url) else: images.append(url) if response_format is not None and hasattr(response_format, "model_json_schema"): result = client.call( prompt=user_text, schema=response_format, model=model, system_prompt=system_prompt, images=images if images else None, temperature=0, ) return _json.dumps(result.model_dump(), ensure_ascii=False) else: return client.call_raw( prompt=user_text, model=model, system_prompt=system_prompt, images=images if images else None, ) class HtmlVariant(BaseModel): html : str description: str changes: list[str] class HtmlVariantsResponse(BaseModel): variants : list[HtmlVariant] def get_openai_request(messages, format, openai_key): """OpenAI APIを呼び出ぁE"" client = LLMClient() response = _ask_raw_hf([{"role":"user","content":p}], model, model="meta-llama/Llama-3.3-70B-Instruct", messages=messages, top_p=1, frequency_penalty=0, presence_penalty=0, response_format=format, temperature=0.7 # バリエーションを�Eすため少し高めに設宁E ) return response @customtracer def html2variants(original_html: str, change_points: str, openai_key=os.environ.get('OPENAI_KEY')): """ input1 (text):

title

input2 (text): タイトルに下線を表示 input3 (text): default output1 (json): html """ print(datetime.now(pytz.timezone('Asia/Tokyo')).strftime("%Y-%m-%d %H:%M:%S"), __name__) if openai_key == "default" or not openai_key: openai_key = os.environ.get('OPENAI_KEY', '') if openai_key: os.environ['OPENAI_API_KEY'] = openai_key # HTMLの構造を簡潔に要紁E��長すぎる場合�E要紁E��E html_summary = original_html[:5000] # 最初�E5000斁E��を使用 if len(original_html) > 5000: html_summary += "\n\n[以下省略...]" # プロンプトを構篁E prompt = f"""以下�E允E�EHTMLと変更点の説明を基に、指定数のHTMLバリアントを生�Eしてください、E 【�EのHTML、E {html_summary} 【変更点の説明、E {change_points} 【要件、E 1. 允E�EHTMLの構造とスタイルを可能な限り維持すめE 2. 変更点の説明に基づぁE��、指定数のHTMLバリアントを生�Eする 3. バリアント�E完�EなHTMLドキュメントとして返す�E�E!DOCTYPE html>からまで�E�E 4. 画像パス、CSSパス、JavaScriptパスなどは允E�EHTMLからそ�Eまま維持すめE 5. 変更するのは主にチE��ストコンチE��チE��、その周辺のチE��イン�E�フォントサイズ、色、レイアウト、余白、スタイルなど�E�でぁE 6. 変更点周辺のチE��インを変更することで、より効果的な表現を実現してください 7. ただし、変更点以外�E部刁E��ロゴ、ナビゲーション、フチE��ー、その他�Eセクション�E��EチE��インは維持してください 8. 允E�EHTMLのすべての要素�E�ESS、画像、JavaScript、メタタグなど�E�を完�Eに保持する 【�E力形式、E - variants: 持E��数のHtmlVariantオブジェクト�EリスチE - HtmlVariantには以下を含める: - html: 完�EなHTMLドキュメンチE - description: こ�Eバリアント�E説明(変更点の要紁E��E0斁E��程度�E�E - changes: 具体的な変更点のリスト(各頁E��は30斁E��程度�E�E """ messages = [ { "role": "system", "content": """あなた�EHTMLの専門家です。�EのHTMLと変更点の説明を基に、指定数のHTMLバリアントを生�Eしてください、E バリアント�E完�EなHTMLドキュメントとして返し、�EのHTMLの構造とスタイルを可能な限り維持しながら、変更点を反映してください、E 変更点周辺のチE��イン�E�フォントサイズ、色、レイアウト、余白、スタイルなど�E�も変更可能です、E"", }, { "role": "user", "content": prompt }, ] try: result = get_openai_request(messages, HtmlVariantsResponse, openai_key) return result except Exception as e: print(f"[html2variants] エラー: {e}") import traceback print(traceback.format_exc()) # エラー時�E空のレスポンスを返す return HtmlVariantsResponse(variants=[])