feat: add public model catalog discovery
This commit is contained in:
+87
-1
@@ -10,7 +10,14 @@ from django.test import Client, TestCase, override_settings
|
||||
from django.utils import timezone
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from apps.billing.models import CallRecord, ExchangeRate, PointsLedger, RechargeOrder
|
||||
from apps.ai.models import AiModel, ModelAlias
|
||||
from apps.billing.models import (
|
||||
CallRecord,
|
||||
ExchangeRate,
|
||||
PointsLedger,
|
||||
PricingRule,
|
||||
RechargeOrder,
|
||||
)
|
||||
from apps.users.models import ApiKey, UserWallet
|
||||
|
||||
|
||||
@@ -77,6 +84,32 @@ class PortalAccountFlowTests(TestCase):
|
||||
status=status,
|
||||
)
|
||||
|
||||
def create_model_alias(
|
||||
self,
|
||||
*,
|
||||
alias: str,
|
||||
operation_type: str = ModelAlias.OperationType.TITLE,
|
||||
capabilities: list[str] | None = None,
|
||||
api_type: str = AiModel.ApiType.CHAT,
|
||||
url: str = "https://provider-secret.example/v1/chat/completions",
|
||||
model_sku: str = "secret-sku-gpt-5.5",
|
||||
) -> ModelAlias:
|
||||
ai_model = AiModel.objects.create(
|
||||
name=f"{alias}-{uuid.uuid4().hex[:8]}",
|
||||
url=url,
|
||||
model=model_sku,
|
||||
api_type=api_type,
|
||||
api_key_encrypted="encrypted-provider-key",
|
||||
capabilities=capabilities if capabilities is not None else ["text"],
|
||||
extra_body={"internal": "provider-extra-secret"},
|
||||
is_active=True,
|
||||
)
|
||||
return ModelAlias.objects.create(
|
||||
alias=alias,
|
||||
operation_type=operation_type,
|
||||
ai_model=ai_model,
|
||||
)
|
||||
|
||||
def test_signup_creates_unverified_user_wallet_with_zero_points_and_no_ledger(self):
|
||||
suffix = uuid.uuid4().hex[:8]
|
||||
email = f"signup-{suffix}@example.com"
|
||||
@@ -164,6 +197,59 @@ class PortalAccountFlowTests(TestCase):
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertTrue(response["Location"].startswith("/login?next="))
|
||||
|
||||
def test_models_page_requires_session_login(self):
|
||||
response = self.client.get("/models")
|
||||
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertTrue(response["Location"].startswith("/login?next="))
|
||||
|
||||
def test_models_page_lists_public_aliases_prices_and_unpriced_state(self):
|
||||
user = self.create_verified_user()
|
||||
title_alias = self.create_model_alias(alias="title-standard", capabilities=["text"])
|
||||
image_alias = self.create_model_alias(
|
||||
alias="image-edit",
|
||||
operation_type=ModelAlias.OperationType.IMAGE,
|
||||
capabilities=["image", "vision"],
|
||||
api_type=AiModel.ApiType.IMAGES_EDITS,
|
||||
url="https://provider-secret.example/v1/images/edits",
|
||||
model_sku="secret-sku-image-2",
|
||||
)
|
||||
PricingRule.objects.create(
|
||||
operation_type=title_alias.operation_type,
|
||||
alias=title_alias.alias,
|
||||
resolution="",
|
||||
points_cost=2,
|
||||
)
|
||||
PricingRule.objects.create(
|
||||
operation_type=image_alias.operation_type,
|
||||
alias=image_alias.alias,
|
||||
resolution="1k",
|
||||
points_cost=12,
|
||||
is_active=False,
|
||||
)
|
||||
self.client.force_login(user)
|
||||
|
||||
response = self.client.get("/models")
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(response.context["models"]), 2)
|
||||
self.assertContains(response, "可用模型")
|
||||
self.assertContains(response, "title-standard")
|
||||
self.assertContains(response, "生成标题")
|
||||
self.assertContains(response, "默认")
|
||||
self.assertContains(response, "2 点")
|
||||
self.assertContains(response, "image-edit")
|
||||
self.assertContains(response, "生成图片")
|
||||
self.assertContains(response, "需要")
|
||||
self.assertContains(response, "暂未定价")
|
||||
self.assertNotContains(response, "secret-sku")
|
||||
self.assertNotContains(response, "provider-secret.example")
|
||||
self.assertNotContains(response, "encrypted-provider-key")
|
||||
self.assertNotContains(response, "provider-extra-secret")
|
||||
self.assertNotContains(response, "api_key")
|
||||
self.assertNotContains(response, "api_key_encrypted")
|
||||
self.assertNotContains(response, "extra_body")
|
||||
|
||||
def test_create_api_key_shows_plaintext_once_and_stores_only_hash(self):
|
||||
user = self.create_verified_user()
|
||||
self.client.force_login(user)
|
||||
|
||||
Reference in New Issue
Block a user