entari-plugin-hyw 4.0.0rc5__py3-none-any.whl → 4.0.0rc7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of entari-plugin-hyw might be problematic. Click here for more details.

@@ -22,7 +22,7 @@ from arclet.entari.event.command import CommandReceive
22
22
  from .modular_pipeline import ModularPipeline
23
23
  from .history import HistoryManager
24
24
  from .render_vue import ContentRenderer, get_content_renderer
25
- from .misc import process_onebot_json, process_images, resolve_model_name, render_refuse_answer, REFUSE_ANSWER_MARKDOWN
25
+ from .misc import process_onebot_json, process_images, resolve_model_name, render_refuse_answer, render_image_unsupported, REFUSE_ANSWER_MARKDOWN
26
26
  from arclet.entari.event.lifespan import Cleanup
27
27
 
28
28
  import os
@@ -93,6 +93,7 @@ class ModelConfig:
93
93
  model_provider: Optional[str] = None
94
94
  input_price: Optional[float] = None
95
95
  output_price: Optional[float] = None
96
+ image_input: bool = True
96
97
 
97
98
 
98
99
  @dataclass
@@ -117,11 +118,10 @@ class HywConfig(BasicConfModel):
117
118
  instruct: Optional[ModelConfig] = None
118
119
  qa: Optional[ModelConfig] = None
119
120
  main: Optional[ModelConfig] = None # Summary stage
121
+ vision: Optional[ModelConfig] = None # Vision description stage
120
122
 
121
123
  # Search/Fetch Settings
122
- search_engine: str = "bing"
123
- enable_domain_blocking: bool = True
124
- page_content_mode: str = "text"
124
+ search_engine: str = "google"
125
125
 
126
126
  # Rendering Settings
127
127
  headless: bool = False
@@ -131,10 +131,10 @@ class HywConfig(BasicConfModel):
131
131
  # Bot Behavior
132
132
  save_conversation: bool = False
133
133
  reaction: bool = False
134
- quote: bool = True
134
+ quote: bool = False
135
135
 
136
136
  # UI Theme
137
- theme_color: str = "#ef4444"
137
+ theme_color: str = "#ff0000"
138
138
 
139
139
  def __post_init__(self):
140
140
  """Parse and normalize theme color after initialization."""
@@ -146,6 +146,8 @@ class HywConfig(BasicConfModel):
146
146
  self.qa = ModelConfig(**self.qa)
147
147
  if isinstance(self.main, dict):
148
148
  self.main = ModelConfig(**self.main)
149
+ if isinstance(self.vision, dict):
150
+ self.vision = ModelConfig(**self.vision)
149
151
 
150
152
  def get_model_config(self, stage: str) -> Dict[str, Any]:
151
153
  """
@@ -170,6 +172,9 @@ class HywConfig(BasicConfModel):
170
172
  secondary = self.main
171
173
  elif stage == "main":
172
174
  primary = self.main
175
+ elif stage == "vision":
176
+ primary = self.vision
177
+ secondary = self.main # Fallback to main if vision not fully configured
173
178
 
174
179
  # Build result with fallback logic
175
180
  def resolve(field_name: str, is_essential: bool = True):
@@ -315,14 +320,66 @@ async def process_request(
315
320
 
316
321
  images, err = await process_images(mc, vision_model)
317
322
 
318
- # Start preparing render tab (async)
323
+ # Check image input support
324
+ model_cfg_dict = next((m for m in conf.models if m.get("name") == model), None)
325
+ image_input_supported = True
326
+ if model_cfg_dict:
327
+ image_input_supported = model_cfg_dict.get("image_input", True)
328
+
329
+ # Log inferenced content mode
330
+ inferred_content_mode = "image" if image_input_supported else "text"
331
+ logger.info(f"Process Request: Model '{model}' Image Input: {image_input_supported} -> Mode: {inferred_content_mode}")
332
+
333
+ if images and not image_input_supported:
334
+ logger.warning(f"Model '{model}' does not support images, but user sent {len(images)} images.")
335
+
336
+ # Start renderer for the unsupported card
337
+ renderer = await get_content_renderer()
338
+ render_tab_task = asyncio.create_task(renderer.prepare_tab())
339
+
340
+ # Wait for tab and render unsupported
341
+ try:
342
+ tab_id = await render_tab_task
343
+ except Exception as e:
344
+ tab_id = None
345
+
346
+ import tempfile
347
+ with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tf:
348
+ output_path = tf.name
349
+
350
+ render_ok = await render_image_unsupported(
351
+ renderer=renderer,
352
+ output_path=output_path,
353
+ theme_color=conf.theme_color,
354
+ tab_id=tab_id
355
+ )
356
+
357
+ if render_ok:
358
+ with open(output_path, "rb") as f:
359
+ img_data = base64.b64encode(f.read()).decode()
360
+ await session.send(MessageChain(Image(src=f'data:image/png;base64,{img_data}')))
361
+ if os.path.exists(output_path):
362
+ os.remove(output_path)
363
+ return
364
+
319
365
  renderer = await get_content_renderer()
320
366
  render_tab_task = asyncio.create_task(renderer.prepare_tab())
321
367
  tab_id = None
322
368
 
323
369
  # Call Pipeline directly
324
370
  safe_input = msg_text
325
- pipeline = ModularPipeline(conf)
371
+
372
+ async def send_noti(msg: str):
373
+ try:
374
+ # Send simple text notification
375
+ if conf.quote:
376
+ await session.send([Quote(session.event.message.id), msg])
377
+ else:
378
+ await session.send(msg)
379
+ except Exception as e:
380
+ logger.warning(f"Failed to send notification: {e}")
381
+
382
+ pipeline = ModularPipeline(conf, send_func=send_noti)
326
383
  try:
327
384
  resp = await pipeline.execute(
328
385
  safe_input,
@@ -385,6 +442,7 @@ async def process_request(
385
442
  tab_id=tab_id,
386
443
  )
387
444
  else:
445
+ logger.info(f"Rendering card with {len(structured.get('references', []))} references...")
388
446
  render_ok = await renderer.render(
389
447
  markdown_content=content,
390
448
  output_path=output_path,
@@ -396,6 +454,7 @@ async def process_request(
396
454
  stages_used=final_resp.get("stages_used", []),
397
455
  theme_color=conf.theme_color,
398
456
  )
457
+ logger.info(f"Render completed: {render_ok}")
399
458
 
400
459
  # Send & Save
401
460
  if not render_ok:
@@ -442,10 +501,13 @@ async def process_request(
442
501
  if conf.save_conversation and sent_id:
443
502
  try:
444
503
  # Pass web_results to save fetched pages as markdown, and output image
504
+ # Also pass vision_trace and instruct_traces for dedicated logs
445
505
  history_manager.save_to_disk(
446
506
  sent_id,
447
507
  web_results=final_resp.get("web_results"),
448
- image_path=output_path if 'output_path' in locals() else None
508
+ image_path=output_path if 'output_path' in locals() else None,
509
+ vision_trace=final_resp.get("vision_trace"),
510
+ instruct_traces=final_resp.get("instruct_traces"),
449
511
  )
450
512
  except Exception as e:
451
513
  logger.warning(f"Failed to save conversation: {e}")