feat(product-suite): decouple ai writing gateway
This commit is contained in:
@@ -541,6 +541,7 @@ class AITests(TempDirMixin, unittest.TestCase):
|
||||
def test_cmhub_analyze_product_images_uses_vision_alias_and_safe_metadata(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg, key_path = self._cmhub_config(temp_dir)
|
||||
cfg["ai"]["backend"] = "direct"
|
||||
first = os.path.join(temp_dir, "first.png")
|
||||
second = os.path.join(temp_dir, "second.jpg")
|
||||
with open(first, "wb") as fh:
|
||||
@@ -602,6 +603,7 @@ class AITests(TempDirMixin, unittest.TestCase):
|
||||
def test_cmhub_analyze_product_images_requires_vision_alias_and_local_limits(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg, key_path = self._cmhub_config(temp_dir)
|
||||
cfg["ai"]["backend"] = "direct"
|
||||
source = os.path.join(temp_dir, "source.jpg")
|
||||
with open(source, "wb") as fh:
|
||||
fh.write(b"source")
|
||||
|
||||
@@ -127,6 +127,33 @@ class ProductSuiteGuiTests(TempDirMixin, unittest.TestCase):
|
||||
model["api_key"] = "test-image-key"
|
||||
appconfig.save_ai_models_config(models_config, path=models_path)
|
||||
|
||||
def _configure_cmhub_vision(self, config):
|
||||
ai_config = appconfig.ai_config(config)
|
||||
ai_config["cmhub"].update(
|
||||
{
|
||||
"base_url": "https://cmhub.example.com",
|
||||
"vision_alias": "vision-standard",
|
||||
}
|
||||
)
|
||||
config["ai"] = ai_config
|
||||
appconfig.save_cmhub_config(
|
||||
{"api_key": "test-key"},
|
||||
path=config["cmhub_config_path"],
|
||||
)
|
||||
cmhub_models.cache_model_catalog(
|
||||
"https://cmhub.example.com",
|
||||
[
|
||||
{
|
||||
"alias": "vision-standard",
|
||||
"operation_type": "vision",
|
||||
"requires_image": True,
|
||||
"pricing_status": "priced",
|
||||
"prices": [{"points_cost": 2}],
|
||||
}
|
||||
],
|
||||
)
|
||||
self.addCleanup(cmhub_models.clear_model_catalog_cache)
|
||||
|
||||
def _create_history_job(
|
||||
self,
|
||||
project,
|
||||
@@ -209,6 +236,7 @@ class ProductSuiteGuiTests(TempDirMixin, unittest.TestCase):
|
||||
|
||||
self.assertTrue(tab.generate_button.isEnabled())
|
||||
self.assertFalse(tab.ai_write_button.isEnabled())
|
||||
self.assertIn("默认网关", tab.ai_write_button.toolTip())
|
||||
self.assertFalse(tab.resume_submitted_button.isHidden())
|
||||
self.assertTrue(tab.resume_submitted_button.isEnabled())
|
||||
self.assertEqual(
|
||||
@@ -219,6 +247,106 @@ class ProductSuiteGuiTests(TempDirMixin, unittest.TestCase):
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_direct_generation_gateway_keeps_ai_write_available_with_cmhub_vision(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
config = self._config(temp_dir)
|
||||
config["ai"] = appconfig.ai_config(config)
|
||||
config["ai"]["backend"] = "direct"
|
||||
config["ai"]["cmhub"].update(
|
||||
{
|
||||
"base_url": "https://cmhub.example.com",
|
||||
"vision_alias": "vision-standard",
|
||||
}
|
||||
)
|
||||
appconfig.save_cmhub_config(
|
||||
{"api_key": "test-key"},
|
||||
path=config["cmhub_config_path"],
|
||||
)
|
||||
self._configure_direct_image_gateway(config)
|
||||
project, assets = self._create_project_with_assets(temp_dir, config, 1)
|
||||
tab = ProductSuiteTab(config=config, db_path=config["db_path"])
|
||||
self.addCleanup(tab.close)
|
||||
self.addCleanup(cmhub_models.clear_model_catalog_cache)
|
||||
state = tab._displayed_state
|
||||
state.account_alias = "alias-a"
|
||||
state.item_id = project.item_id
|
||||
state.project_id = project.id
|
||||
state.project_binding_state = project.binding_state
|
||||
tab._load_state(state)
|
||||
cmhub_models.cache_model_catalog(
|
||||
"https://cmhub.example.com",
|
||||
[
|
||||
{
|
||||
"alias": "vision-standard",
|
||||
"operation_type": "vision",
|
||||
"requires_image": True,
|
||||
"pricing_status": "priced",
|
||||
"prices": [{"points_cost": 2}],
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
self.assertTrue(tab.generate_button.isEnabled())
|
||||
self.assertTrue(tab.ai_write_button.isEnabled())
|
||||
self.assertEqual("", tab.ai_write_button.toolTip())
|
||||
with mock.patch.object(tab, "_confirm_ai_write_request") as confirm:
|
||||
tab.start_ai_write()
|
||||
|
||||
state_arg, asset_ids, points_cost = confirm.call_args.args
|
||||
self.assertIs(state_arg, state)
|
||||
self.assertEqual((assets[0].id,), asset_ids)
|
||||
self.assertEqual("2", cmhub_models.format_points_cost(points_cost))
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_direct_generation_and_ai_write_configuration_errors_are_independent(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
config = self._config(temp_dir)
|
||||
config["ai"] = appconfig.ai_config(config)
|
||||
config["ai"]["backend"] = "direct"
|
||||
config["ai"]["cmhub"].update(
|
||||
{
|
||||
"base_url": "https://cmhub.example.com",
|
||||
"vision_alias": "vision-standard",
|
||||
}
|
||||
)
|
||||
self._configure_direct_image_gateway(config)
|
||||
project, _assets = self._create_project_with_assets(temp_dir, config, 1)
|
||||
tab = ProductSuiteTab(config=config, db_path=config["db_path"])
|
||||
self.addCleanup(tab.close)
|
||||
state = tab._displayed_state
|
||||
state.account_alias = "alias-a"
|
||||
state.item_id = project.item_id
|
||||
state.project_id = project.id
|
||||
state.project_binding_state = project.binding_state
|
||||
tab._load_state(state)
|
||||
|
||||
cases = (
|
||||
("base_url", "", "尚未配置默认网关地址", "test-key"),
|
||||
("vision_alias", "", "尚未选择图片理解模型", "test-key"),
|
||||
("vision_alias", "vision-standard", "尚未配置默认网关 API Key", ""),
|
||||
)
|
||||
for key, value, expected_error, api_key in cases:
|
||||
with self.subTest(key=key, expected_error=expected_error):
|
||||
tab.config["ai"]["cmhub"].update(
|
||||
{
|
||||
"base_url": "https://cmhub.example.com",
|
||||
"vision_alias": "vision-standard",
|
||||
key: value,
|
||||
}
|
||||
)
|
||||
appconfig.save_cmhub_config(
|
||||
{"api_key": api_key},
|
||||
path=tab.cmhub_config_path,
|
||||
)
|
||||
self.assertEqual(expected_error, tab._ai_write_config_error())
|
||||
tab._apply_running_state(state)
|
||||
self.assertTrue(tab.generate_button.isEnabled())
|
||||
self.assertFalse(tab.ai_write_button.isEnabled())
|
||||
self.assertIn(expected_error, tab.ai_write_button.toolTip())
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_direct_gateway_preflight_and_confirmation_do_not_call_cmhub_catalog(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
config = self._config(temp_dir)
|
||||
@@ -1321,6 +1449,7 @@ class ProductSuiteGuiTests(TempDirMixin, unittest.TestCase):
|
||||
def test_ai_write_uses_first_eight_originals_in_source_order_regardless_of_checks(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
config = self._config(temp_dir)
|
||||
self._configure_cmhub_vision(config)
|
||||
project, assets = self._create_project_with_assets(temp_dir, config, 9)
|
||||
tab = ProductSuiteTab(config=config, db_path=config["db_path"])
|
||||
self.addCleanup(tab.close)
|
||||
@@ -3155,6 +3284,7 @@ class ProductSuiteGuiTests(TempDirMixin, unittest.TestCase):
|
||||
def test_temporary_draft_allows_local_work_but_blocks_shopee_pull_and_recovers(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
config = self._config(temp_dir)
|
||||
self._configure_cmhub_vision(config)
|
||||
accounts.create_account("主店", "alias-a", debug_port=9222, config=config)
|
||||
tab = ProductSuiteTab(config=config, db_path=config["db_path"])
|
||||
self.addCleanup(tab.close)
|
||||
|
||||
@@ -408,7 +408,7 @@ class WorkerTests(unittest.TestCase):
|
||||
"补充要求",
|
||||
"输出语言:繁体中文",
|
||||
image_paths=["first.jpg", "second.jpg"],
|
||||
config={"ai": {"backend": "cmhub"}},
|
||||
config={"ai": {"backend": "direct"}},
|
||||
cmhub_config_path="cmhub.json",
|
||||
)
|
||||
expected = {
|
||||
|
||||
Reference in New Issue
Block a user