feat(product-suite): decouple ai writing gateway

This commit is contained in:
chengma
2026-07-23 10:42:55 +08:00
parent f7c9d761ee
commit 3d4976913e
10 changed files with 183 additions and 29 deletions
+130
View File
@@ -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)