From 2787bd9df9fd7387da91c459327c60453cb8480c Mon Sep 17 00:00:00 2001 From: HuangHai <10402852@qq.com> Date: Mon, 12 Jan 2026 08:49:17 +0800 Subject: [PATCH] 'commit' --- .../__pycache__/Setting.cpython-310.pyc | Bin 533 -> 533 bytes Apps/XinDianTu/ReadImageKit.py | 98 +++++++++--------- Apps/XinDianTu/Service.py | 14 +-- .../__pycache__/ReadImageKit.cpython-310.pyc | Bin 0 -> 34793 bytes .../__pycache__/Service.cpython-310.pyc | Bin 10690 -> 10672 bytes 5 files changed, 56 insertions(+), 56 deletions(-) create mode 100644 Apps/XinDianTu/__pycache__/ReadImageKit.cpython-310.pyc diff --git a/Apps/XinDianTu/Config/__pycache__/Setting.cpython-310.pyc b/Apps/XinDianTu/Config/__pycache__/Setting.cpython-310.pyc index 23fe7e24d5ac0022bb3de4d7f4ba4cac22f25f33..c433eb7ad3e1c02b073543bfe2d6d9d08dbb9601 100644 GIT binary patch delta 36 rcmbQrGL?llpO=@50SK~PQZm;}{HNTw dict: if device_info is None: logger.warning("未提供动态设备信息,使用通用回退配置。") - device_info = XinDianTuReadImageKit._FALLBACK_DEVICE_INFO + device_info = ReadImageKit._FALLBACK_DEVICE_INFO prompt = ( "仅输出JSON对象(不含任何说明文字),请找到图片中带有“全部时段”字样的按钮区域(通常在价格表下方,是一个带有右箭头的文字按钮)。\n" @@ -226,7 +226,7 @@ class XinDianTuReadImageKit: loop = asyncio.get_event_loop() resp = await loop.run_in_executor( None, - lambda: XinDianTuReadImageKit._client.chat.completions.create( + lambda: ReadImageKit._client.chat.completions.create( model=VL_MODEL_NAME, messages=[ { @@ -247,12 +247,12 @@ class XinDianTuReadImageKit: ) content = resp.choices[0].message.content or "" - raw = XinDianTuReadImageKit._extract_json(content) + raw = ReadImageKit._extract_json(content) try: data = json.loads(raw) if isinstance(data, dict) and (data.get("bounds") or data.get("bounds_norm")): - data = XinDianTuReadImageKit._add_center(data, device_info) + data = ReadImageKit._add_center(data, device_info) # 只返回中心坐标 return { "uia_center_x": data.get("uia_center_x"), @@ -268,7 +268,7 @@ class XinDianTuReadImageKit: async def find_station_coordinate_first_page(image_url: str, station_name: str, device_info: dict = None) -> dict: if device_info is None: logger.warning("未提供动态设备信息,使用通用回退配置。") - device_info = XinDianTuReadImageKit._FALLBACK_DEVICE_INFO + device_info = ReadImageKit._FALLBACK_DEVICE_INFO prompt = ( "仅输出JSON对象(不含任何说明文字)。" @@ -283,7 +283,7 @@ class XinDianTuReadImageKit: loop = asyncio.get_event_loop() resp = await loop.run_in_executor( None, - lambda: XinDianTuReadImageKit._client.chat.completions.create( + lambda: ReadImageKit._client.chat.completions.create( model=VL_MODEL_NAME, messages=[ { @@ -299,14 +299,14 @@ class XinDianTuReadImageKit: ) content = resp.choices[0].message.content or "" - raw = XinDianTuReadImageKit._extract_json(content) + raw = ReadImageKit._extract_json(content) try: data = json.loads(raw) if isinstance(data, dict) and ( data.get("station_name_bounds") or data.get("station_name_bounds_norm") or data.get( "bounds") or data.get("bounds_norm")): - data = XinDianTuReadImageKit._add_click_point(data, device_info, anchor="station_text") + data = ReadImageKit._add_click_point(data, device_info, anchor="station_text") return { "uia_center_x": data.get("uia_center_x"), "uia_center_y": data.get("uia_center_y") @@ -319,12 +319,12 @@ class XinDianTuReadImageKit: async def parse_first_level_image_url(image_url: str, device_info: dict = None) -> list: if device_info is None: logger.warning("未提供动态设备信息,使用通用回退配置。") - device_info = XinDianTuReadImageKit._FALLBACK_DEVICE_INFO + device_info = ReadImageKit._FALLBACK_DEVICE_INFO loop = asyncio.get_event_loop() resp = await loop.run_in_executor( None, - lambda: XinDianTuReadImageKit._client.chat.completions.create( + lambda: ReadImageKit._client.chat.completions.create( model=VL_MODEL_NAME, messages=[ { @@ -337,7 +337,7 @@ class XinDianTuReadImageKit: }, }, {"type": "text", "text": json.dumps(device_info, ensure_ascii=False)}, - {"type": "text", "text": XinDianTuReadImageKit._prompt}, + {"type": "text", "text": ReadImageKit._prompt}, ], }, ], @@ -345,18 +345,18 @@ class XinDianTuReadImageKit: ) content = resp.choices[0].message.content or "" - raw = XinDianTuReadImageKit._extract_json(content) + raw = ReadImageKit._extract_json(content) try: data = json.loads(raw) if isinstance(data, list): # 过滤掉 None (即被 _add_click_point 排除掉的顶部项) - data = [XinDianTuReadImageKit._add_click_point(x, device_info, anchor="station_text") for x in data if + data = [ReadImageKit._add_click_point(x, device_info, anchor="station_text") for x in data if x.get("b_use", 1) == 1] data = [x for x in data if x is not None] elif isinstance(data, dict): if data.get("b_use", 1) == 1: - data = XinDianTuReadImageKit._add_click_point(data, device_info, anchor="station_text") + data = ReadImageKit._add_click_point(data, device_info, anchor="station_text") data = [data] if data is not None else [] else: data = [] @@ -397,7 +397,7 @@ class XinDianTuReadImageKit: if name: idxs.append(i) tasks.append(asyncio.create_task( - XinDianTuReadImageKit.find_station_coordinate_first_page(image_url, name, device_info) + ReadImageKit.find_station_coordinate_first_page(image_url, name, device_info) )) if tasks: results = await asyncio.gather(*tasks, return_exceptions=True) @@ -418,7 +418,7 @@ class XinDianTuReadImageKit: """ 统一入口:混合识别模式 """ - return await XinDianTuReadImageKit.get_stations_hybrid(image_path, uploader, cdn_domain) + return await ReadImageKit.get_stations_hybrid(image_path, uploader, cdn_domain) @staticmethod async def parse_vl_image(vl_image_url, json_metadata, device_info=None): @@ -453,7 +453,7 @@ class XinDianTuReadImageKit: loop = asyncio.get_event_loop() resp = await loop.run_in_executor( None, - lambda: XinDianTuReadImageKit._client.chat.completions.create( + lambda: ReadImageKit._client.chat.completions.create( model=VL_MODEL_NAME, messages=[ { @@ -468,7 +468,7 @@ class XinDianTuReadImageKit: ) content = resp.choices[0].message.content or "" - raw = XinDianTuReadImageKit._extract_json(content) + raw = ReadImageKit._extract_json(content) final_stations = [] try: @@ -529,7 +529,7 @@ class XinDianTuReadImageKit: 混合识别模式:图形学切片 + 大模型小图 OCR """ # 1. 图形学切片 - segments = XinDianTuReadImageKit.get_card_segments(image_path) + segments = ReadImageKit.get_card_segments(image_path) if not segments: return [] @@ -544,7 +544,7 @@ class XinDianTuReadImageKit: # 记录上传后的 URL 供识别使用 seg["patch_url"] = patch_url - tasks.append(XinDianTuReadImageKit.recognize_card_text(patch_url)) + tasks.append(ReadImageKit.recognize_card_text(patch_url)) # 等待所有 OCR 完成 results = await asyncio.gather(*tasks) @@ -772,7 +772,7 @@ class XinDianTuReadImageKit: loop = asyncio.get_event_loop() resp = await loop.run_in_executor( None, - lambda: XinDianTuReadImageKit._client.chat.completions.create( + lambda: ReadImageKit._client.chat.completions.create( model=VL_MODEL_NAME, messages=[ { @@ -820,7 +820,7 @@ class XinDianTuReadImageKit: """ if device_info is None: logger.warning("未提供动态设备信息,使用通用回退配置。") - device_info = XinDianTuReadImageKit._FALLBACK_DEVICE_INFO + device_info = ReadImageKit._FALLBACK_DEVICE_INFO prompt = ( "分析图片中是否存在覆盖在主界面上的广告弹窗(Popup Ad)。" @@ -834,7 +834,7 @@ class XinDianTuReadImageKit: loop = asyncio.get_event_loop() resp = await loop.run_in_executor( None, - lambda: XinDianTuReadImageKit._client.chat.completions.create( + lambda: ReadImageKit._client.chat.completions.create( model=VL_MODEL_NAME_AD, # 使用更强的视觉模型 messages=[ { @@ -853,7 +853,7 @@ class XinDianTuReadImageKit: ) content = resp.choices[0].message.content or "" - raw = XinDianTuReadImageKit._extract_json(content) + raw = ReadImageKit._extract_json(content) try: data = json.loads(raw) @@ -861,7 +861,7 @@ class XinDianTuReadImageKit: if has_ad and data.get("close_button_bounds"): # 使用现有的辅助方法转换坐标 temp_obj = {"bounds": data.get("close_button_bounds")} - XinDianTuReadImageKit._add_click_point(temp_obj, device_info) + ReadImageKit._add_click_point(temp_obj, device_info) return { "has_ad": True, "uia_center_x": temp_obj.get("uia_center_x"), @@ -912,7 +912,7 @@ class XinDianTuReadImageKit: """ if device_info is None: logger.warning("未提供动态设备信息,使用通用回退配置。") - device_info = XinDianTuReadImageKit._FALLBACK_DEVICE_INFO + device_info = ReadImageKit._FALLBACK_DEVICE_INFO # 视觉解析提示词:约束输出字段与格式,避免模型输出说明文字 prompt = ( @@ -928,7 +928,7 @@ class XinDianTuReadImageKit: loop = asyncio.get_event_loop() def _do_request(url_val): - return XinDianTuReadImageKit._client.chat.completions.create( + return ReadImageKit._client.chat.completions.create( model=VL_MODEL_NAME, messages=[ { @@ -957,7 +957,7 @@ class XinDianTuReadImageKit: # 如果是媒体格式或数据检查错误 if 'InvalidParameter.DataInspection' in str(err_code) or 'media format' in str(e).lower(): logger.warning(f"Image URL rejected ({err_code}). Attempting Base64 fallback: {image_url}") - base64_str = await XinDianTuReadImageKit._download_as_base64(image_url) + base64_str = await ReadImageKit._download_as_base64(image_url) if base64_str: # 简单推断格式,默认 jpeg ext = "jpeg" @@ -982,7 +982,7 @@ class XinDianTuReadImageKit: return [] content = resp.choices[0].message.content or "" - raw = XinDianTuReadImageKit._extract_json(content) + raw = ReadImageKit._extract_json(content) try: # 反序列化模型返回的 JSON @@ -1069,8 +1069,8 @@ class XinDianTuReadImageKit: hourly = [] for r in rows: # 起止时间转分钟 - s = XinDianTuReadImageKit._to_minutes(r.get("start")) - e = XinDianTuReadImageKit._to_minutes(r.get("end")) + s = ReadImageKit._to_minutes(r.get("start")) + e = ReadImageKit._to_minutes(r.get("end")) if e <= s: continue cur = s @@ -1078,8 +1078,8 @@ class XinDianTuReadImageKit: # 下一小时边界;不超过区间终点 nxt = min(e, ((cur // 60) + 1) * 60) hourly.append({ - "start": XinDianTuReadImageKit._fmt(cur), - "end": XinDianTuReadImageKit._fmt(nxt), + "start": ReadImageKit._fmt(cur), + "end": ReadImageKit._fmt(nxt), "price_kwh": r.get("price_kwh"), "electric_fee_kwh": r.get("electric_fee_kwh"), "service_fee_kwh": r.get("service_fee_kwh"), @@ -1120,10 +1120,10 @@ class XinDianTuReadImageKit: """ if device_info is None: logger.warning("未提供动态设备信息,使用通用回退配置。") - device_info = XinDianTuReadImageKit._FALLBACK_DEVICE_INFO + device_info = ReadImageKit._FALLBACK_DEVICE_INFO # 启动寻找“全部时段”按钮的任务,为后续可能的点击做准备 - button_task = asyncio.create_task(XinDianTuReadImageKit.find_all_time_button_coordinate(image_url, device_info)) + button_task = asyncio.create_task(ReadImageKit.find_all_time_button_coordinate(image_url, device_info)) prompt = ( "仅输出JSON对象(不含任何说明文字)。" @@ -1139,7 +1139,7 @@ class XinDianTuReadImageKit: loop = asyncio.get_event_loop() resp = await loop.run_in_executor( None, - lambda: XinDianTuReadImageKit._client.chat.completions.create( + lambda: ReadImageKit._client.chat.completions.create( model=VL_MODEL_NAME, messages=[ { @@ -1158,7 +1158,7 @@ class XinDianTuReadImageKit: ) content = resp.choices[0].message.content or "" - raw = XinDianTuReadImageKit._extract_json(content) + raw = ReadImageKit._extract_json(content) result = {} try: @@ -1200,14 +1200,14 @@ class XinDianTuReadImageKit: # MD5 -> URL 的映射,用于去重 md5_to_url = {} for u in image_urls: - m = await XinDianTuReadImageKit._fetch_md5(u) + m = await ReadImageKit._fetch_md5(u) if m and m not in md5_to_url: md5_to_url[m] = u unique_urls = list(md5_to_url.values()) # 合并时段结果 combined = [] for u in unique_urls: - rows = await XinDianTuReadImageKit.parse_price_schedule(station_name, u, device_info=device_info) + rows = await ReadImageKit.parse_price_schedule(station_name, u, device_info=device_info) if rows: combined.extend(rows) return combined @@ -1230,8 +1230,8 @@ class XinDianTuReadImageKit: # 预处理:转换为分钟区间 intervals = [] for r in rows: - s = XinDianTuReadImageKit._to_minutes(r.get("start")) - e = XinDianTuReadImageKit._to_minutes(r.get("end")) + s = ReadImageKit._to_minutes(r.get("start")) + e = ReadImageKit._to_minutes(r.get("end")) if e <= s: continue s = max(0, s) @@ -1256,8 +1256,8 @@ class XinDianTuReadImageKit: best_overlap = overlap best = it result.append({ - "start": XinDianTuReadImageKit._fmt(hs), - "end": XinDianTuReadImageKit._fmt(he), + "start": ReadImageKit._fmt(hs), + "end": ReadImageKit._fmt(he), "price_kwh": best["price_kwh"] if best else None, "electric_fee_kwh": best["electric_fee_kwh"] if best else None, "service_fee_kwh": best["service_fee_kwh"] if best else None, @@ -1269,7 +1269,7 @@ async def test1(): # 测试新电途第一层结构的读取 url = "https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/Temp/8fd79c68-fec6-4ca7-8d8e-fbff3c6862c8.jpg" print(f"Testing First Level with URL: {url}") - result = await XinDianTuReadImageKit.parse_first_level_image_url(url) + result = await ReadImageKit.parse_first_level_image_url(url) print("First Level Result:") print(json.dumps(result, ensure_ascii=False, indent=2)) @@ -1278,7 +1278,7 @@ async def test2(station_name: str): # 测试新电途第二层结构的读取 url = "https://dsideal.obs.myhuaweicloud.com/HuangHai/Temp/SecondPage.jpg" print(f"Testing address extraction from: {url}") - result = await XinDianTuReadImageKit.parse_address(station_name, url) + result = await ReadImageKit.parse_address(station_name, url) result["station_name"] = station_name print("Address result:") print(json.dumps(result, ensure_ascii=False, indent=2)) @@ -1290,8 +1290,8 @@ async def test3(station_name: str): "https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/Temp/XinDianTu/1.jpg", "https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/Temp/XinDianTu/2.jpg", ] - rows = await XinDianTuReadImageKit.parse_price_schedule_multi(station_name, samples) - hourly = XinDianTuReadImageKit.hourly_full_day(rows) + rows = await ReadImageKit.parse_price_schedule_multi(station_name, samples) + hourly = ReadImageKit.hourly_full_day(rows) print(json.dumps(hourly, ensure_ascii=False, indent=2)) diff --git a/Apps/XinDianTu/Service.py b/Apps/XinDianTu/Service.py index 3cc1402..19f10a2 100644 --- a/Apps/XinDianTu/Service.py +++ b/Apps/XinDianTu/Service.py @@ -11,7 +11,7 @@ project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(_ if project_root not in sys.path: sys.path.append(project_root) -from Apps.XinDianTu.XinDianTuReadImageKit import XinDianTuReadImageKit +from Apps.XinDianTu.ReadImageKit import ReadImageKit from DbKit.Db import Db from Config.Config import DB_URL from Model.StationProfile import StationProfile @@ -46,7 +46,7 @@ class XinDianTuService: """ 基于 VL 模式处理场站列表 """ - station_list = await XinDianTuReadImageKit.parse_vl_image(vl_image_url, json_metadata, device_info=device_info) + station_list = await ReadImageKit.parse_vl_image(vl_image_url, json_metadata, device_info=device_info) if not station_list: return [] @@ -163,7 +163,7 @@ class XinDianTuService: """ 混合模式处理场站列表 (图形学切片 + OCR) """ - station_list = await XinDianTuReadImageKit.parse_hybrid_image(local_image_path, uploader, cdn_domain) + station_list = await ReadImageKit.parse_hybrid_image(local_image_path, uploader, cdn_domain) if not station_list: return [] @@ -241,7 +241,7 @@ class XinDianTuService: return processed_stations async def process_station_list(self, list_url: str, device_info: dict = None) -> list: - station_list = await XinDianTuReadImageKit.parse_first_level_image_url(list_url, device_info=device_info) + station_list = await ReadImageKit.parse_first_level_image_url(list_url, device_info=device_info) if not station_list: return [] @@ -338,7 +338,7 @@ class XinDianTuService: async def process_station_address(self, station_name: str, detail_url: str, device_info: dict = None) -> dict: logger.info(f"\n[Service] Processing Address for '{station_name}' from: {detail_url}") - address_data = await XinDianTuReadImageKit.parse_address(station_name, detail_url, device_info=device_info) + address_data = await ReadImageKit.parse_address(station_name, detail_url, device_info=device_info) address = address_data.get("address") if address: address = address.strip() @@ -493,8 +493,8 @@ class XinDianTuService: async def process_price_schedule(self, station_name: str, schedule_urls: list, device_info: dict = None): logger.info(f"\n[Service] Processing Price Schedule for '{station_name}'") - rows = await XinDianTuReadImageKit.parse_price_schedule_multi(station_name, schedule_urls, device_info=device_info) - hourly_schedule = XinDianTuReadImageKit.hourly_full_day(rows) + rows = await ReadImageKit.parse_price_schedule_multi(station_name, schedule_urls, device_info=device_info) + hourly_schedule = ReadImageKit.hourly_full_day(rows) if hourly_schedule: logger.info(f" - Got {len(hourly_schedule)} hourly records.") diff --git a/Apps/XinDianTu/__pycache__/ReadImageKit.cpython-310.pyc b/Apps/XinDianTu/__pycache__/ReadImageKit.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bb6bbb401f28af02a5a1f85c1b9dcce30dbdc726 GIT binary patch literal 34793 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 F5dcJ!4S@gv delta 69 zcmdlGd?=VVpO=@50SHdmresEMhsp42rP^