Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """Unit tests for dynamic LLM-backed silicon sampling runtime.""" | |
| from __future__ import annotations | |
| import json | |
| import sys | |
| import unittest | |
| from pathlib import Path | |
| from typing import Any | |
| ROOT = Path(__file__).resolve().parents[1] | |
| sys.path.insert(0, str(ROOT)) | |
| from silicon_llm import ( # noqa: E402 | |
| build_silicon_llm_system_prompt, | |
| build_silicon_prompt_preview, | |
| build_silicon_llm_response_contract, | |
| parse_silicon_agent_response, | |
| run_silicon_llm_sampling, | |
| ) | |
| QUESTIONS = [ | |
| { | |
| "id": "q_likert_5", | |
| "title": "ν μ λΆ κ΅μ μ΄μμ μ΄λ»κ² νκ°νμλκΉ?", | |
| "kind": "likert", | |
| "scale": 5, | |
| "lowLabel": "λ§€μ° λΆμ ", | |
| "highLabel": "λ§€μ° κΈμ ", | |
| }, | |
| { | |
| "id": "q_likert_4", | |
| "title": "μ§μ μλ£ μ κ·Όμ±μ λ§μ‘±νμλκΉ?", | |
| "kind": "likert", | |
| "scale": 4, | |
| }, | |
| { | |
| "id": "q_open", | |
| "title": "κ°μ₯ λ¨Όμ ν΄κ²°ν΄μΌ ν λ¬Έμ λ 무μμ λκΉ?", | |
| "kind": "open", | |
| }, | |
| { | |
| "id": "q_categorical", | |
| "title": "μΆμμ κ°μ₯ μ€μν κ²μ νλλ§ κ³ λ₯΄μμμ€.", | |
| "kind": "categorical", | |
| "options": [ | |
| {"id": "money", "label": "λ"}, | |
| {"id": "honor", "label": "λͺ μ"}, | |
| {"id": "health", "label": "건κ°"}, | |
| ], | |
| }, | |
| ] | |
| class FakeLLM: | |
| def __init__(self) -> None: | |
| self.calls: list[dict[str, Any]] = [] | |
| def complete_agent(self, *, agent: dict[str, Any], questions: list[dict[str, Any]], response_contract: dict[str, Any]) -> str: | |
| self.calls.append({"agent": agent, "questions": questions, "response_contract": response_contract}) | |
| return json.dumps( | |
| { | |
| "answers": { | |
| "q_likert_5": {"value": 4, "reason": "μ μ± νκ°λ λμ²΄λ‘ κΈμ μ μ λλ€."}, | |
| "q_likert_4": {"value": 2, "reason": "μλ£ μ κ·Όμ±μ μ§μμ λ°λΌ λΆμ‘±ν©λλ€."}, | |
| "q_open": {"text": "λ¬Όκ°μ μλ£ μ κ·Όμ± κ°μ μ΄ κ°μ₯ μκΈν©λλ€.", "theme": "μλ£", "rationale": "μνλΉμ μλ£ μ΄μ© κ²½νμ ν¨κ» κ³ λ €νμ΅λλ€."}, | |
| "q_categorical": {"optionId": "health", "label": "건κ°", "rationale": "κ³ λ Ή κ°μ‘± λλ΄ κ²½ν λλ¬Έμ 건κ°μ μ°μ νμ΅λλ€."}, | |
| } | |
| }, | |
| ensure_ascii=False, | |
| ) | |
| class SiliconLLMRuntimeTests(unittest.TestCase): | |
| def test_contract_is_dynamic_for_question_mix(self) -> None: | |
| contract = build_silicon_llm_response_contract(QUESTIONS) | |
| answer_properties = contract["schema"]["properties"]["answers"]["properties"] | |
| self.assertEqual(set(answer_properties), {"q_likert_5", "q_likert_4", "q_open", "q_categorical"}) | |
| self.assertEqual(answer_properties["q_likert_5"]["properties"]["value"]["minimum"], 1) | |
| self.assertEqual(answer_properties["q_likert_5"]["properties"]["value"]["maximum"], 5) | |
| self.assertEqual(answer_properties["q_likert_4"]["properties"]["value"]["maximum"], 4) | |
| self.assertIn("rationale", answer_properties["q_likert_4"]["required"]) | |
| self.assertIn("text", answer_properties["q_open"]["required"]) | |
| self.assertIn("rationale", answer_properties["q_open"]["required"]) | |
| self.assertEqual(answer_properties["q_categorical"]["properties"]["optionId"]["enum"], ["money", "honor", "health"]) | |
| def test_prompt_preview_uses_personalized_backend_prompt(self) -> None: | |
| system_prompt = build_silicon_llm_system_prompt() | |
| self.assertIn("1μΈμΉ", system_prompt) | |
| self.assertIn("μ΅μ λ κ°μ§", system_prompt) | |
| self.assertIn("μΌλ°λ‘ ", system_prompt) | |
| preview = build_silicon_prompt_preview( | |
| { | |
| "config": { | |
| "sampleSize": 1, | |
| "genders": [{"id": "female", "enabled": True, "weight": 1}], | |
| "ages": [{"id": "40s", "enabled": True, "weight": 1}], | |
| "locations": [{"id": "seoul", "enabled": True, "weight": 1}], | |
| "locationOptions": [{"id": "seoul", "label": "μμΈ", "parentRegion": "seoul", "level": "sido"}], | |
| "questions": QUESTIONS, | |
| } | |
| } | |
| ) | |
| self.assertEqual(preview["systemContent"], system_prompt) | |
| self.assertIn("required_json_contract", preview["userContent"]) | |
| self.assertIn("q_categorical", preview["userContent"]) | |
| def test_parser_extracts_all_dynamic_answers_from_fenced_json(self) -> None: | |
| raw = """ | |
| μκ° κ³Όμ μ μλ΅ν©λλ€. | |
| ```json | |
| { | |
| "answers": { | |
| "q_likert_5": {"value": "5", "reason": "κ°ν κΈμ "}, | |
| "q_likert_4": {"score": 3, "reason": "λ³΄ν΅ μ΄μ"}, | |
| "q_open": {"answer": "κ΅ν΅κ³Ό λλ΄μ΄ νμν©λλ€", "topic": "κ΅ν΅"}, | |
| "q_categorical": {"label": "건κ°", "rationale": "μν μμ μ μ μ λΌκ³ 보μμ΅λλ€."} | |
| } | |
| } | |
| ``` | |
| """ | |
| parsed = parse_silicon_agent_response(raw, QUESTIONS, respondent_id="R0001") | |
| self.assertEqual(len(parsed["likertAnswers"]), 2) | |
| self.assertEqual(len(parsed["categoricalAnswers"]), 1) | |
| self.assertEqual(len(parsed["openAnswers"]), 1) | |
| self.assertEqual(parsed["likertAnswers"][0]["value"], 5) | |
| self.assertEqual(parsed["likertAnswers"][1]["value"], 3) | |
| self.assertEqual(parsed["likertAnswers"][0]["rationale"], "κ°ν κΈμ ") | |
| self.assertEqual(parsed["categoricalAnswers"][0]["optionId"], "health") | |
| self.assertEqual(parsed["categoricalAnswers"][0]["label"], "건κ°") | |
| self.assertEqual(parsed["openAnswers"][0]["theme"], "κ΅ν΅") | |
| self.assertTrue(parsed["openAnswers"][0]["rationale"]) | |
| def test_runtime_calls_one_llm_agent_for_all_questions_and_builds_stats(self) -> None: | |
| fake = FakeLLM() | |
| payload = { | |
| "config": { | |
| "sampleSize": 2, | |
| "genders": [{"id": "male", "enabled": True, "weight": 1}, {"id": "female", "enabled": True, "weight": 1}], | |
| "ages": [{"id": "30s", "enabled": True, "weight": 2}], | |
| "locations": [{"id": "seoul", "enabled": True, "weight": 2}], | |
| "locationOptions": [{"id": "seoul", "label": "μμΈ", "parentRegion": "seoul", "level": "sido", "defaultWeight": 100, "short": "μμΈ", "group": "μλ"}], | |
| "personaAttributes": [{"id": "occ_office", "enabled": True, "weight": 2}], | |
| "nemotronFields": ["persona", "sex", "age"], | |
| "questions": QUESTIONS, | |
| "seed": 42, | |
| }, | |
| "execution": {"max_agents": 2}, | |
| } | |
| result = run_silicon_llm_sampling(payload, llm=fake) | |
| self.assertEqual(len(fake.calls), 2) | |
| self.assertTrue(all(len(call["questions"]) == 4 for call in fake.calls)) | |
| self.assertEqual(len(result["respondents"]), 2) | |
| self.assertEqual(len(result["likertAnswers"]), 4) | |
| self.assertEqual(len(result["categoricalAnswers"]), 2) | |
| self.assertEqual(len(result["openAnswers"]), 2) | |
| self.assertTrue(all(answer.get("rationale") for answer in result["likertAnswers"])) | |
| self.assertTrue(all(answer.get("rationale") for answer in result["categoricalAnswers"])) | |
| self.assertTrue(all(answer.get("rationale") for answer in result["openAnswers"])) | |
| self.assertEqual([stat["questionId"] for stat in result["questionStats"]], ["q_likert_5", "q_likert_4", "q_open", "q_categorical"]) | |
| self.assertEqual(result["questionStats"][0]["distribution"][3]["count"], 2) | |
| self.assertEqual(result["questionStats"][3]["distribution"][2]["count"], 2) | |
| self.assertEqual(result["regionStats"][0]["respondents"], 2) | |
| self.assertEqual(result["llmTrace"]["calls"], 2) | |
| if __name__ == "__main__": | |
| unittest.main(verbosity=2) | |