Spaces:
Sleeping
Sleeping
| from openai import os | |
| from src.clients.llm_client import LLMClient | |
| import json | |
| import pandas as pd | |
| from pydantic import BaseModel | |
| from enum import Enum | |
| import base64 | |
| from io import BytesIO | |
| from PIL import Image | |
| from functools import cache | |
| 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, re | |
| client = LLMClient() | |
| # Extract system prompt and user content from messages list | |
| 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, | |
| ) | |
| import json | |
| 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 UIoption(str, Enum): | |
| element1 = "バナー/動画" | |
| element2 = "CTA" | |
| element3 = "チE��スチE | |
| element4 = "フォーム" | |
| class Component(BaseModel): | |
| component_large: str | |
| component_middle: str | |
| component_small: list[str] | |
| UIelement: UIoption | |
| class Components(BaseModel): | |
| components: list[Component] | |
| def ask_raw(messages): | |
| client = LLMClient() | |
| # HF: beta.parse not available; use _ask_raw_hf instead | |
| response = client.chat.completions.create( | |
| model='meta-llama/Llama-3.3-70B-Instruct', | |
| messages=messages, | |
| top_p=1, | |
| frequency_penalty=0, | |
| presence_penalty=0, | |
| response_format=Components, | |
| temperature=0 | |
| ) | |
| return response.choices[0].message.content | |
| @customtracer | |
| def base64img2component(p, image64, openai_key=os.environ.get('OPENAI_KEY')): | |
| """ | |
| input1 (text): 13: ※金融犯罪にご注愁E手口はこちら、E38: ▼ご利用条件はこちら、E77: ピンチ�E時�E、E133: アコム一抁E409: WEB完結カードを作らぁE415: ご契紁E�E翌日から最大30日間��利0冁E421: 借りられめE0刁E�� 644: 今すぐお申し込み 722: 実質年玁E3.0%~18.0%ご融賁E��E1丁E�E~800丁E�E 760: 以前ご利用があっぁE761: ご増額をご希望のお客さまはこちめE784: お客さまはこちめE819: *お申し込み時間めE��査によりご希望に沿えなぁE��合がござぁE��す、E868: お借�E可能かすぐに刁E��めE秒スピ�Eド診断 977: 侁E22 1055: ご年叁E税込) 1067: 侁E250 1146: 他社お借�E顁E1249: 診断開姁E1323: ※クレジチE��カードでのショチE��ング、E��行でのお借�E(銀行カードローン、住宁E��ーン、�E動車ローンなど)を除ぁE��、キャチE��ングめE��ードローンのお借�E状況をご�E力ください、E1498: 借りるなめE1558: アコム一抁E1710: 20刁E��借りられめE1835: アコムなら最短20刁E��お借�Eが可能!※すぐにお��が忁E��とぁE��時�E、本ペ�Eジの申込ボタンから早速お申し込みくだ 1960: ※お申し込み時間めE��査によりご希望に添えなぁE��合がござぁE��す、E2045: カードを作らずWEB完絁E2165: お申し込み〜お借�EまでWEBだけで完結できます。ご希望ぁE��だければカードレスでご契紁E��ただけます、E2354: |30日間��利ぁE冁E2356: 契紁E�E翌日から 2470: はじめてご利用のお客さまは、契紁E�E翌日から最大30日間��利ぁE冁E 2663: たっぁEスチE��チE!(最短20刁E 2757: 申し込みから借りるまでの流れ※お申し込み時間めE��査によりご希望に添えなぁE��合がござぁE��す、E2937: お申し込み・1忁E��書類提出(審査)お申し込みぁE��だぁE��後、忁E��書類を提�EしてぁE��だき審査に進みます、E3131: 2ご契紁E�Eお借�E 3194: 審査結果の冁E��にご同意いただけましたら、契紁E��続きは完亁E��なります。契紁E���E、すぐにお借�EぁE��だけます。ご希望ぁE��だければカードレスでご契紁E��ただけます、E3335: 忁E��書類とは? 3405: 本人確認書顁E免許証など) 3455: (該当する方のみ)+収�E証明書 3488: ※「当社のご利用において50丁E�Eを趁E��るご契紁E��行うお客さま」と「他社を含めたお借�E総額が100丁E�Eを趁E��るお客「さま」につぁE��は、収入証明書も忁E��で 3633: アコムの 3664: よくある質啁E3777: 申し込み編 3892: Q勤務�Eに在籍確認�E電話がかかってきま 3961: 原則、実施しません。※原則、E��話での在籍確認�Eせずに書面めE��申告�E容での確認を実施します。もし実施が忁E��となる場合でも、お客さまの同意を得ずに実施することはありませんので、ご安忁E��ださい、E4135: Q契紁E��ると、忁E��カードが自宁E��郵送さ 4159: れるんですか? 4205: ぁE��え。カードレスでご契紁E��続きぁE��だくことも可能です、E4296: 自宁E��勤務�Eに何か書類が送られてくる 4320: ことはありますか? 4366: 原則、E��付しません、E郵送契紁E��選択された場合や、書面の郵送受け取りを選 4418: んだ場合等を除ぁE 5914: は、ご返済シミュレーションをご利用ぁE5943: ださい、E5992: ペ�Eジ上部に戻る▲ 7671: ご増額をご希望のお客さまはこちめE7671: 以前ご利用があったお客さまはこちめE8033: 今すぐお申し込み | |
| input2 (text): スクショ | |
| input3 (text): default | |
| output1 (json): 頁E�� | |
| """ | |
| print(datetime.now(pytz.timezone('Asia/Tokyo')).strftime("%Y-%m-%d %H:%M:%S"), f"base64img2component:", image64[0:30]) | |
| if openai_key == "default": | |
| os.environ['OPENAI_API_KEY'] = os.environ.get('OPENAI_KEY') | |
| else: | |
| os.environ['OPENAI_API_KEY'] = openai_key | |
| messages=[ | |
| { | |
| "role": "system", | |
| "content": """ | |
| ■構�E要素名�Eアウト�EチE��サンプル | |
| [ | |
| {"component_large":"啁E��/サービスの特徴","component_middle":"アコム", "component_small":[], "UIelement":"チE��スチE}, | |
| {"component_large":"FAQ/よくある質啁E,"component_middle":"よくあるご質啁E, "component_small":["自宁E��勤務�Eに何か書類が送られてくることはありますか�E�E,"家族割などの割引�Eありますか�E�E], "UIelement":"表絁E��"} | |
| ] | |
| """ | |
| }, | |
| { | |
| "role": "user", | |
| "content": [{"type": "text", "text":p}] | |
| }, | |
| ] | |
| messages[1]["content"].insert(0, {"type": "image_url", "image_url": {"url":"data:image/png;base64,"+image64}}) | |
| # OpenAI 側の認証エラーなどを�E示皁E��メチE��ージとして上位に伝搬させめE | |
| try: | |
| return ask_raw(messages) | |
| except openai.AuthenticationError as e: | |
| # API キー / 絁E��設定�E問題を含むエラー冁E��をラチE�Eして投げ直ぁE | |
| # 呼び出し�E�E�EE Origin 側など�E�でこ�EメチE��ージをキャチE��してユーザに表示できる | |
| raise RuntimeError(f"[base64img2component] OpenAI AuthenticationError: {e}") from e |