from __future__ import annotations import unittest from pydantic import ValidationError from schemas import AnalysisConfig from services.post_call.analyzer import ( _json_schema, _parse_json_content, _validated_result, ) FIELDS = [ { "id": "intent", "name": "customer_intent", "type": "enum", "description": "客户意向", "enum_values": ["high", "low"], }, { "id": "follow_up", "name": "need_follow_up", "type": "boolean", "description": "是否需要跟进", "enum_values": [], }, ] class AnalysisConfigTest(unittest.TestCase): def test_enabled_analysis_requires_model_and_fields(self): with self.assertRaises(ValidationError): AnalysisConfig(enabled=True) def test_field_names_must_be_unique(self): field = { "id": "one", "name": "customer_name", "type": "string", "description": "客户姓名", } with self.assertRaises(ValidationError): AnalysisConfig( enabled=True, model_resource_id="model_001", fields=[field, {**field, "id": "two"}], ) class StructuredExtractionTest(unittest.TestCase): def test_schema_marks_every_field_nullable_and_required(self): schema = _json_schema(FIELDS) self.assertEqual( schema["required"], ["customer_intent", "need_follow_up"] ) self.assertEqual( schema["properties"]["customer_intent"]["enum"], ["high", "low", None], ) def test_invalid_values_are_normalized_to_null(self): result = _validated_result( {"customer_intent": "medium", "need_follow_up": "yes"}, FIELDS, ) self.assertEqual( result, {"customer_intent": None, "need_follow_up": None}, ) def test_json_parser_accepts_fenced_model_output(self): self.assertEqual( _parse_json_content('```json\n{"need_follow_up": true}\n```'), {"need_follow_up": True}, ) if __name__ == "__main__": unittest.main()