ksaa 2025.7.7.0__py3-none-any.whl → 2025.7.13.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. kotonebot/backend/context/context.py +23 -10
  2. kotonebot/errors.py +5 -1
  3. kotonebot/kaa/common.py +2 -976
  4. kotonebot/kaa/config/__init__.py +62 -0
  5. kotonebot/kaa/config/const.py +255 -0
  6. kotonebot/kaa/config/migrations/__init__.py +28 -0
  7. kotonebot/kaa/config/migrations/_idol.py +106 -0
  8. kotonebot/kaa/config/migrations/_v1_to_v2.py +203 -0
  9. kotonebot/kaa/config/migrations/_v2_to_v3.py +126 -0
  10. kotonebot/kaa/config/migrations/_v3_to_v4.py +29 -0
  11. kotonebot/kaa/config/migrations/_v4_to_v5.py +26 -0
  12. kotonebot/kaa/config/migrations/_v5_to_v6.py +134 -0
  13. kotonebot/kaa/config/produce.py +255 -0
  14. kotonebot/kaa/config/schema.py +236 -0
  15. kotonebot/kaa/config/upgrade.py +63 -0
  16. kotonebot/kaa/game_ui/commu_event_buttons.py +3 -0
  17. kotonebot/kaa/game_ui/schedule.py +1 -1
  18. kotonebot/kaa/main/gr.py +821 -172
  19. kotonebot/kaa/main/kaa.py +23 -13
  20. kotonebot/kaa/metadata.py +45 -0
  21. kotonebot/kaa/resources/__pycache__/__init__.cpython-310.pyc +0 -0
  22. kotonebot/kaa/tasks/R.py +126 -126
  23. kotonebot/kaa/tasks/daily/acquire_activity_funds.py +1 -1
  24. kotonebot/kaa/tasks/daily/acquire_presents.py +1 -1
  25. kotonebot/kaa/tasks/daily/assignment.py +1 -1
  26. kotonebot/kaa/tasks/daily/capsule_toys.py +1 -1
  27. kotonebot/kaa/tasks/daily/club_reward.py +1 -1
  28. kotonebot/kaa/tasks/daily/contest.py +1 -1
  29. kotonebot/kaa/tasks/daily/mission_reward.py +1 -1
  30. kotonebot/kaa/tasks/daily/purchase.py +1 -1
  31. kotonebot/kaa/tasks/daily/upgrade_support_card.py +1 -1
  32. kotonebot/kaa/tasks/end_game.py +1 -1
  33. kotonebot/kaa/tasks/produce/cards.py +1 -1
  34. kotonebot/kaa/tasks/produce/common.py +3 -2
  35. kotonebot/kaa/tasks/produce/in_purodyuusu.py +9 -7
  36. kotonebot/kaa/tasks/produce/non_lesson_actions.py +3 -2
  37. kotonebot/kaa/tasks/produce/produce.py +27 -22
  38. kotonebot/kaa/tasks/start_game.py +1 -1
  39. {ksaa-2025.7.7.0.dist-info → ksaa-2025.7.13.0.dist-info}/METADATA +1 -1
  40. {ksaa-2025.7.7.0.dist-info → ksaa-2025.7.13.0.dist-info}/RECORD +170 -158
  41. /kotonebot/kaa/sprites/{2f4f3d81-2a8c-49d3-84a8-4d1205237ed4.png → 065de266-800e-4ebf-bab1-a37038e531d8.png} +0 -0
  42. /kotonebot/kaa/sprites/{177ee196-1013-487e-9944-64c4a9b803ef.png → 0951b840-439e-4289-991e-51b5b2df0bb2.png} +0 -0
  43. /kotonebot/kaa/sprites/{6d4337f4-e30c-44eb-bab9-220a46c0c96f.png → 09ca39cd-c964-4258-a860-6a327e31713c.png} +0 -0
  44. /kotonebot/kaa/sprites/{9e861b2e-f896-4738-b0d0-9b703395720d.png → 0b166ce2-85b0-4207-b4ee-e720462cf9ab.png} +0 -0
  45. /kotonebot/kaa/sprites/{1cd922b1-cd9c-4b60-b7e7-014c59217cb0.png → 0d10fa02-b8e7-405a-a463-83f472807a39.png} +0 -0
  46. /kotonebot/kaa/sprites/{c692a9b3-8a2a-42f1-8f63-ad8bd553272d.png → 0edc4c9d-9249-4bf0-86ad-c9fee3ee06f7.png} +0 -0
  47. /kotonebot/kaa/sprites/{f5917c99-185e-4bd9-b367-972c77accb44.png → 10d7c07d-9731-4b2a-bc92-bfb822616303.png} +0 -0
  48. /kotonebot/kaa/sprites/{59997849-5a5a-4589-a4ff-e91a789fc68d.png → 13ebdaaf-dee5-48be-963e-c2e6915b2b00.png} +0 -0
  49. /kotonebot/kaa/sprites/{b720a22b-a2f1-4686-969d-2a2edd8fb96b.png → 14e920fb-7410-4927-96e1-c40211069182.png} +0 -0
  50. /kotonebot/kaa/sprites/{489feedd-f44e-4714-ad24-b53630dfcf27.png → 17d9408b-b429-402c-9d06-f2a0b2b1abe2.png} +0 -0
  51. /kotonebot/kaa/sprites/{835a1f3e-5a06-4490-bc2e-c6d3d8edc1fd.png → 2228a02e-fec3-4bb7-ad29-d7ef0d7b7a90.png} +0 -0
  52. /kotonebot/kaa/sprites/{9d94c24c-5aab-4fb6-8fa7-902cebac134c.png → 28b29b73-758c-41ef-8829-4b93d7a6f424.png} +0 -0
  53. /kotonebot/kaa/sprites/{e64c9477-35f7-4f05-995f-f3f38bb7db66.png → 2b845193-37f8-4e17-9fd2-52765977b1fa.png} +0 -0
  54. /kotonebot/kaa/sprites/{21fe29c2-f49b-473f-8ac3-896b4d3c72f5.png → 31f239cb-58f7-4fe9-95e4-15572afa9855.png} +0 -0
  55. /kotonebot/kaa/sprites/{466524da-0d9e-424f-82eb-d6e6d3145bd3.png → 32fa7671-2413-400f-9bad-3fd7859840e4.png} +0 -0
  56. /kotonebot/kaa/sprites/{80c45554-0758-47eb-b9d7-d8c10f462ae5.png → 33dfe24e-9cc8-43c9-98a8-999e850b778a.png} +0 -0
  57. /kotonebot/kaa/sprites/{84c0f8bf-c670-47d4-8d5c-06de599f7c40.png → 34050b3d-1684-403d-95b1-8ad7ff2a85bb.png} +0 -0
  58. /kotonebot/kaa/sprites/{30ff50f2-7ab2-4a1d-88db-fd6deaba328e.png → 387b6503-d6c8-40ab-8cad-2a81021b6103.png} +0 -0
  59. /kotonebot/kaa/sprites/{1d714b45-6b20-40ba-8e0b-e7c106f0c8f3.png → 3995bbdb-4b0c-4327-b299-7d105a78e977.png} +0 -0
  60. /kotonebot/kaa/sprites/{4112f697-094b-4046-bfac-409f156784b0.png → 43648de0-a0dc-4d0b-b081-ddb4a6aae9c4.png} +0 -0
  61. /kotonebot/kaa/sprites/{899ad2c0-7b23-4b77-aed4-34ba4911672b.png → 44713a59-3d15-427a-af43-27efdc1b2b20.png} +0 -0
  62. /kotonebot/kaa/sprites/{4670fd78-3748-4df3-968b-25c8246da92b.png → 46189b9d-16fd-4385-9654-2a6fa95bc933.png} +0 -0
  63. /kotonebot/kaa/sprites/{f9e8cde8-fda0-4436-8072-6bc32c3c0b8e.png → 4660a922-bb9a-4543-b11a-d7b3be41e42e.png} +0 -0
  64. /kotonebot/kaa/sprites/{b2f31f86-b7ae-4eb1-8042-d14c5b226714.png → 476c4b40-a024-4253-bd57-b775b1559c44.png} +0 -0
  65. /kotonebot/kaa/sprites/{c639b2f6-35f2-4924-9e81-878637c176a6.png → 488c8e34-9a36-4335-8a69-c9288e3344d7.png} +0 -0
  66. /kotonebot/kaa/sprites/{f18c683d-1eb2-4279-a05c-c411683354df.png → 48a169b5-e3ad-41c8-9895-5fff217a24a3.png} +0 -0
  67. /kotonebot/kaa/sprites/{bfd495eb-7ec2-47d7-aff2-59c1a663be5d.png → 48d52db5-9d6f-4d6d-a8a9-56ec3e03cf2e.png} +0 -0
  68. /kotonebot/kaa/sprites/{d07f0d30-465e-4b4e-803f-a81aeabdd1e8.png → 4ca16d51-1b1c-4174-98df-dce028749eb0.png} +0 -0
  69. /kotonebot/kaa/sprites/{54f5e4d6-44f9-4249-bf80-aaaacf0a8d52.png → 4ee4dde9-378f-4ef3-b1f3-29bbb3d9e073.png} +0 -0
  70. /kotonebot/kaa/sprites/{025f1786-cd28-4a08-ad81-178d267dbb1a.png → 4f36ddbb-967e-41d5-9bdb-05bb8f906227.png} +0 -0
  71. /kotonebot/kaa/sprites/{b73fa422-bf9c-43aa-ad80-ae92286042e6.png → 51c39af7-efe6-4763-a85c-f1275e7cf4e8.png} +0 -0
  72. /kotonebot/kaa/sprites/{31dd40b0-1c07-4d6c-aabe-fd3e4895f4df.png → 524134df-5ade-4eb0-903f-dbae8d2a6e00.png} +0 -0
  73. /kotonebot/kaa/sprites/{d7d6ace9-35f1-4c71-b4c1-9de938b254f4.png → 582e8afb-81d9-433b-9297-2741f78224c0.png} +0 -0
  74. /kotonebot/kaa/sprites/{e6a16a1e-e821-45f0-bc64-f2e0dab7efd7.png → 59d453f1-a2df-4138-9e4e-277f6b636bde.png} +0 -0
  75. /kotonebot/kaa/sprites/{2ffd9c12-0520-4f9c-92b1-bfdef0681583.png → 5b382fe1-da9d-4644-b4e7-aa2759b36b9d.png} +0 -0
  76. /kotonebot/kaa/sprites/{97e33fa0-1442-418d-b393-3b916312c9e1.png → 5ca735d9-04b0-40a4-8eda-adbf9d0ded34.png} +0 -0
  77. /kotonebot/kaa/sprites/{af0f65a5-8d32-4211-86df-66b3fa609462.png → 5cda82c5-6026-4a4b-9447-30779ef07e51.png} +0 -0
  78. /kotonebot/kaa/sprites/{7315c6b9-6fda-4790-8e9a-c8c4220834e1.png → 5e00a181-041a-4456-8850-773f68de8573.png} +0 -0
  79. /kotonebot/kaa/sprites/{0089161a-0dac-41da-97af-b9200339a383.png → 6151e500-a626-44db-89d5-a7b15d99f9aa.png} +0 -0
  80. /kotonebot/kaa/sprites/{898325da-307d-4108-ab4c-25d9ae94ee24.png → 618b8738-c9ae-4def-951f-a3627b26a980.png} +0 -0
  81. /kotonebot/kaa/sprites/{a586f586-85e9-439e-ab3f-905d6cbe6746.png → 661760df-f790-47cb-8ddf-21b684a1096d.png} +0 -0
  82. /kotonebot/kaa/sprites/{5200fbda-653d-4b6f-84d8-15793cc53684.png → 69601752-7606-4af4-9252-097be36eec84.png} +0 -0
  83. /kotonebot/kaa/sprites/{2d0ed04f-777a-4a69-9a58-0be791260dca.png → 69d32f6c-e982-4418-94f9-5a625dc06584.png} +0 -0
  84. /kotonebot/kaa/sprites/{f2d614b3-d3bf-4340-b261-f4c385a59e4e.png → 6c2ba024-4e1e-4a07-9b58-277a1873c279.png} +0 -0
  85. /kotonebot/kaa/sprites/{c9e507d5-94dd-4ff3-b995-70c6cb360095.png → 6cc3d385-7c1a-4df2-92dd-0bc7f4931f2c.png} +0 -0
  86. /kotonebot/kaa/sprites/{b2743383-a3e4-43ff-82a3-3c7c6450fc50.png → 6d7d40e7-8f54-40b5-a900-784e2ced0df5.png} +0 -0
  87. /kotonebot/kaa/sprites/{06e7d3f6-1ab8-4714-8ab5-8af71dcbfa78.png → 721caff2-926b-4778-a20b-77c9fee8f45a.png} +0 -0
  88. /kotonebot/kaa/sprites/{dfb1d18d-b768-46c4-9d31-b654ba7a2b6d.png → 740c5975-00d7-42a7-ad95-cee0d59db3f0.png} +0 -0
  89. /kotonebot/kaa/sprites/{3de5ce1b-f72b-450a-a1de-5a841fbd507a.png → 75972e14-44b8-4ac7-9bfa-a0e0ed563b05.png} +0 -0
  90. /kotonebot/kaa/sprites/{2146a037-c3ad-4c33-834c-ddd7f3b7876c.png → 77a55e26-3901-4be0-9edb-a434c6e5e719.png} +0 -0
  91. /kotonebot/kaa/sprites/{0a3c0a4e-a979-401c-9bf3-a389e8a74e7b.png → 79d26ab2-499d-46a5-b15d-a0d0845fc535.png} +0 -0
  92. /kotonebot/kaa/sprites/{78c0f6b4-c09d-4b44-9b5e-35e1e40dd748.png → 7a72a3ad-666c-478e-a249-2ca7e35f84cb.png} +0 -0
  93. /kotonebot/kaa/sprites/{f9b38a5e-72cb-4b18-8817-18473effd41d.png → 7b58df80-77e7-4a81-84b5-3d7e61f4237e.png} +0 -0
  94. /kotonebot/kaa/sprites/{b974e1ac-1f24-4498-aa84-62cb5c0984e7.png → 80ca25c8-03b6-4ed8-bf0b-36f6ad71ffd4.png} +0 -0
  95. /kotonebot/kaa/sprites/{1cede0b7-5042-481c-b507-957dd98ec17a.png → 83d759a1-04fc-40d3-93d6-d31b4be70e5d.png} +0 -0
  96. /kotonebot/kaa/sprites/{20748b0c-889f-4706-857b-48fc921a88e3.png → 84b25f6f-aeb4-41b0-bb61-9e028ee1173f.png} +0 -0
  97. /kotonebot/kaa/sprites/{6490c5b2-2ed8-44d6-93b8-72d88434b49e.png → 88bcca49-4150-4820-8b47-049f7f1aa604.png} +0 -0
  98. /kotonebot/kaa/sprites/{5367d7ad-5a27-42e4-a7d9-5bf27102f502.png → 88cb2321-ac35-4fe6-a467-19ba5ef3af35.png} +0 -0
  99. /kotonebot/kaa/sprites/{e798ff2f-6f30-4536-923a-a65433817423.png → 897a1e29-c5e2-4c26-a348-6fd7d63c9f09.png} +0 -0
  100. /kotonebot/kaa/sprites/{cdc6e5e2-5b38-4471-b23f-17ec229268db.png → 8a8f4be3-9538-4ead-9002-009432dce534.png} +0 -0
  101. /kotonebot/kaa/sprites/{fc44214e-ef8a-4ea1-baec-35674ce0c4d6.png → 8acb588c-200f-4927-bb50-2f01c7fbf0f5.png} +0 -0
  102. /kotonebot/kaa/sprites/{0913f34e-1790-4afb-af31-9a5e94d54b05.png → 8d093e5a-3ce8-4e67-9e5d-7d91f2dd3b00.png} +0 -0
  103. /kotonebot/kaa/sprites/{3091351b-ab63-4688-8082-32545052d7a8.png → 8e0b582b-68d3-4a4f-93e1-dec23e8e6abf.png} +0 -0
  104. /kotonebot/kaa/sprites/{1762b8dc-abb8-402e-88b9-22111b054d27.png → 8f1413b8-fe01-4a37-9c10-0dcabf092367.png} +0 -0
  105. /kotonebot/kaa/sprites/{688d653e-7ee7-4d41-ac79-b4efd6c3cadd.png → 917cd398-166e-4abe-a769-6d74cfbb611e.png} +0 -0
  106. /kotonebot/kaa/sprites/{adf0eea7-a052-410b-b479-8c672ae38268.png → 92ac2224-ce9d-4ba0-aafc-c627ba97c163.png} +0 -0
  107. /kotonebot/kaa/sprites/{6f06519d-4f33-4418-b4cb-35a7356cc121.png → 9529c488-2256-4a3d-baed-4928c151b1b1.png} +0 -0
  108. /kotonebot/kaa/sprites/{18369504-36b1-4b10-93e6-878c2cae6c8f.png → 9579ad74-b049-4e27-a07c-12537c5ee051.png} +0 -0
  109. /kotonebot/kaa/sprites/{99b58811-42ff-415b-9229-f5c75cbe1a1a.png → 96044a90-a417-4042-a359-ddfd374afd0c.png} +0 -0
  110. /kotonebot/kaa/sprites/{0eb4e53c-f0af-4c86-870c-b1db087d53db.png → 96669532-4774-4c2e-bda0-ea94f3b1d41b.png} +0 -0
  111. /kotonebot/kaa/sprites/{c7e90767-3661-4e86-8c54-8e1d1e83d113.png → 985e8bd4-7658-4da1-beb3-c53220ec1c25.png} +0 -0
  112. /kotonebot/kaa/sprites/{1e398be7-49ac-4eb6-b828-b935f042037a.png → 995b71e0-ce5d-48b7-b1a1-35443a37c295.png} +0 -0
  113. /kotonebot/kaa/sprites/{467fe027-96ba-48b1-963b-75a5c41277c4.png → 9e5202cc-ef3c-433e-8cbb-afa5842f0a34.png} +0 -0
  114. /kotonebot/kaa/sprites/{6faf9942-994d-418a-ae42-25c5fcffa79e.png → 9fd3858a-c2a7-468d-b224-ca6386a08d1e.png} +0 -0
  115. /kotonebot/kaa/sprites/{2712893d-0219-43e1-8de7-c2761456719e.png → 9ff3e793-1c21-45c6-88b5-24543f300f81.png} +0 -0
  116. /kotonebot/kaa/sprites/{4abd8e80-83ef-4d1a-b143-e6ad0ac189ab.png → a49babfb-a958-4de0-b2c5-2c64ce8641fa.png} +0 -0
  117. /kotonebot/kaa/sprites/{126f5161-3567-4c76-8e91-371392e39a9c.png → a5b80b05-f6a2-407e-bf93-27b88bd982d1.png} +0 -0
  118. /kotonebot/kaa/sprites/{05d933de-6274-4d46-a81b-860de1981ebc.png → a622194f-000b-48d9-871f-89e2ba9a249d.png} +0 -0
  119. /kotonebot/kaa/sprites/{7dd1c478-719f-4432-891f-9543064fd1fc.png → a7b99e72-68c1-4b11-994f-a3238bee5fa3.png} +0 -0
  120. /kotonebot/kaa/sprites/{87a59b06-0ac7-4a35-93c4-3705bf9e774a.png → a9ec257b-d82f-4ebf-9b46-1af8836d5768.png} +0 -0
  121. /kotonebot/kaa/sprites/{08f93e03-18c9-42e3-9a2f-7d7954f585b0.png → abeb625a-74c1-45dc-a6c9-2a123dee1ab4.png} +0 -0
  122. /kotonebot/kaa/sprites/{2ed453f3-9c31-4c96-95dd-1a6aa68302f7.png → af04e2ac-bffa-4bfb-9580-c934e403d578.png} +0 -0
  123. /kotonebot/kaa/sprites/{f3e4e9ec-ddd6-42c4-9638-b93ff4e6b514.png → b04f4554-d6ea-4f99-822c-657ad1b9cd1e.png} +0 -0
  124. /kotonebot/kaa/sprites/{d5899bda-b311-469d-b4fb-963799ef1720.png → b06ebc30-305e-4f8a-8a3c-1d91aab4f9c0.png} +0 -0
  125. /kotonebot/kaa/sprites/{bbfb7670-2537-4a92-9a39-487d174f27a0.png → b07b112c-08c8-45ff-b980-105d263ff1c4.png} +0 -0
  126. /kotonebot/kaa/sprites/{4d3e267c-552c-4a65-840a-dc72a61c8db1.png → b1e6c930-f659-4ea8-a694-a4590160b438.png} +0 -0
  127. /kotonebot/kaa/sprites/{e6d0979a-cd27-4933-b528-7777be525ace.png → b34c399b-ea60-4de2-86ee-003d308594c2.png} +0 -0
  128. /kotonebot/kaa/sprites/{d43f214a-4db4-4222-941c-3d3216a0c0c3.png → b4db5745-d7d0-4afb-8962-9f71fc4188c8.png} +0 -0
  129. /kotonebot/kaa/sprites/{4eb9a3a1-da46-493b-a17d-5eb9ef53524c.png → ba45d490-da2e-4c2f-badf-7058f1802ad3.png} +0 -0
  130. /kotonebot/kaa/sprites/{3e9bdd08-3a74-40b3-8320-05ed4e8fe5d7.png → c03c6076-7935-42e7-a2e5-5f74015e92e2.png} +0 -0
  131. /kotonebot/kaa/sprites/{5cff1e6f-81ea-4d4a-88ba-209cf3bbb165.png → c0b5a0a7-0cb7-4d2c-8105-42b434437610.png} +0 -0
  132. /kotonebot/kaa/sprites/{23464a7b-dc7a-439c-86b7-04a5dd506412.png → c2a12970-cfff-4772-a4ec-127f4309f2b5.png} +0 -0
  133. /kotonebot/kaa/sprites/{c1336997-ea27-4d53-9c64-826ca7eca11f.png → c9f0ddc4-832c-42f0-b46d-a2b4326d1a1c.png} +0 -0
  134. /kotonebot/kaa/sprites/{3ddd0976-7c8b-4c67-bac7-a0cc1af3bfad.png → ca37b366-0a29-436c-8c22-78daf4148bfe.png} +0 -0
  135. /kotonebot/kaa/sprites/{c686d99a-248a-460b-a4fe-2fa5b8e9660b.png → cafb66c1-10d3-4612-80f9-f9e183d509c6.png} +0 -0
  136. /kotonebot/kaa/sprites/{8308964d-96d1-4b7e-b0fa-b20163311153.png → cf007582-08d0-4fc7-bc7c-113e211b226a.png} +0 -0
  137. /kotonebot/kaa/sprites/{308818b7-a252-45a6-868d-553c078b3752.png → cf33f626-5944-4dfe-bb46-2976c187f2a9.png} +0 -0
  138. /kotonebot/kaa/sprites/{f957edb2-3534-4d1d-a9be-70b478b2ff63.png → d1f662b1-7aa2-4ccc-a8bf-6e7a94ae2427.png} +0 -0
  139. /kotonebot/kaa/sprites/{6df0db09-9159-43b5-a6b9-43a2dfdafdab.png → d1fff69a-474d-416f-a53f-2a88a4d552c7.png} +0 -0
  140. /kotonebot/kaa/sprites/{e614c8e1-1d7b-4535-a8ba-cbf09fd5b163.png → d251bb28-4d34-4db9-85eb-554a56ac8184.png} +0 -0
  141. /kotonebot/kaa/sprites/{bcb990e6-58ae-460d-859a-812b4121e716.png → d2fe6a19-df40-43f9-8e75-2376e9987290.png} +0 -0
  142. /kotonebot/kaa/sprites/{2154ebd3-9c89-4355-b4f4-a5e18ecf728d.png → d7b786c8-7887-4870-a719-f703945cc6f1.png} +0 -0
  143. /kotonebot/kaa/sprites/{6f638005-aa18-4804-a5fe-269de4d1ad9e.png → d9ac597e-8d6d-4ab3-b865-e68a83563d25.png} +0 -0
  144. /kotonebot/kaa/sprites/{54d71b39-a3f2-4f20-a294-b6b5ef9c56f3.png → db041968-9811-494c-ae2c-1b31d4e1773c.png} +0 -0
  145. /kotonebot/kaa/sprites/{119f04e2-3871-46a8-9d5c-808c641f7aae.png → db2fb64d-3e2d-4cd4-ac3a-a993e9784697.png} +0 -0
  146. /kotonebot/kaa/sprites/{10713c56-e462-4543-8a51-02f220ed6943.png → dd268b19-354f-4e39-a4b4-0578719a40e1.png} +0 -0
  147. /kotonebot/kaa/sprites/{7c40ea85-87f6-4531-a25a-896dd70b49d1.png → deca8ee5-616a-4652-8a37-dab4f34951b6.png} +0 -0
  148. /kotonebot/kaa/sprites/{acd1a611-f93d-4d32-8070-dc325b42eeb9.png → e214cd8e-b79f-42e5-959a-64f745f35896.png} +0 -0
  149. /kotonebot/kaa/sprites/{dd431a8a-3ffa-43d6-96c6-4e84aa946b72.png → e2d11737-e1e2-4056-bd85-7d242c9c3023.png} +0 -0
  150. /kotonebot/kaa/sprites/{4e040068-e2ae-4348-80a2-f113c2426d46.png → e6e33419-ee43-48d1-98c6-a64f07b9e9e9.png} +0 -0
  151. /kotonebot/kaa/sprites/{e007420c-b92b-414c-96a3-d556e3c25cb2.png → e7fb4631-aad6-4fad-934c-72396737a98a.png} +0 -0
  152. /kotonebot/kaa/sprites/{bad07ebd-c8e7-4721-ab74-a38fa30e0401.png → eb56ba19-433e-4bab-9e47-7a2702c83954.png} +0 -0
  153. /kotonebot/kaa/sprites/{fffa0118-dd3a-4d01-8c4e-d43182778391.png → ebef3530-94ab-4ba7-b43e-5b3249286d51.png} +0 -0
  154. /kotonebot/kaa/sprites/{5d5db2d4-2648-40fe-bd17-05aea9afbc7d.png → edcb7ca8-9e3f-4232-b6c9-b7189a62d2ec.png} +0 -0
  155. /kotonebot/kaa/sprites/{acd01a53-c689-4ffd-ae45-744a37c70197.png → ee7c3730-b678-4ffe-a7e5-5637016ce5b4.png} +0 -0
  156. /kotonebot/kaa/sprites/{e87f0760-4bc9-4d7f-91e2-5452ba0fcd9d.png → f270ddb2-fabc-4dd6-818a-c818a44893ed.png} +0 -0
  157. /kotonebot/kaa/sprites/{f26d4e09-2511-48e4-9c69-ba413ddf65e1.png → f2b784ee-eeca-4633-9083-4cb996c26f66.png} +0 -0
  158. /kotonebot/kaa/sprites/{76f43a30-b76d-4648-91b6-49f2786e668d.png → f621f114-11c3-4957-a86c-cb474721d660.png} +0 -0
  159. /kotonebot/kaa/sprites/{5587551f-011c-4f94-86e8-7e81d08c4be2.png → f85c9e53-870d-46e4-9963-c5245d0c5628.png} +0 -0
  160. /kotonebot/kaa/sprites/{5efa51e6-5cb7-4843-9397-8d71c6175fcf.png → f88ee970-84ea-46b2-99e0-d3fe1cde908e.png} +0 -0
  161. /kotonebot/kaa/sprites/{51eac702-ca23-4aba-b75a-cdb03a93a117.png → fa8ee7e4-ee13-497e-856b-e210f6b1f114.png} +0 -0
  162. /kotonebot/kaa/sprites/{6a45398a-4240-4fb7-8926-fa1254125bbf.png → fb00d537-d921-4a5f-9bc7-8aac1b68a71d.png} +0 -0
  163. /kotonebot/kaa/sprites/{2d4001e6-137e-40b2-94b0-ba3ae9e397e4.png → fc23b108-7717-4b16-9e91-aacd5ddcc2ce.png} +0 -0
  164. /kotonebot/kaa/sprites/{d108794a-60b8-4637-bced-84f46140eaac.png → fd3b7b22-7011-4267-8365-64a4933073a4.png} +0 -0
  165. /kotonebot/kaa/sprites/{774ca489-09c2-414e-b27b-f32d3bf6894d.png → fd7ce00d-d45c-468b-a918-f5ded551a17d.png} +0 -0
  166. /kotonebot/kaa/sprites/{e93a983d-b869-45e4-8a5c-cd1c9d511b11.png → ffd7676f-6b57-42d2-9631-bc758d2e0a31.png} +0 -0
  167. {ksaa-2025.7.7.0.dist-info → ksaa-2025.7.13.0.dist-info}/WHEEL +0 -0
  168. {ksaa-2025.7.7.0.dist-info → ksaa-2025.7.13.0.dist-info}/entry_points.txt +0 -0
  169. {ksaa-2025.7.7.0.dist-info → ksaa-2025.7.13.0.dist-info}/licenses/LICENSE +0 -0
  170. {ksaa-2025.7.7.0.dist-info → ksaa-2025.7.13.0.dist-info}/top_level.txt +0 -0
kotonebot/kaa/main/gr.py CHANGED
@@ -16,17 +16,19 @@ import gradio as gr
16
16
 
17
17
  from kotonebot.kaa.main import Kaa
18
18
  from kotonebot.kaa.db import IdolCard
19
+ from kotonebot.backend.context.context import vars
20
+ from kotonebot.errors import ContextNotInitializedError
21
+ from kotonebot.client.host import Mumu12Host, LeidianHost
19
22
  from kotonebot.config.manager import load_config, save_config
20
23
  from kotonebot.config.base_config import UserConfig, BackendConfig
21
24
  from kotonebot.backend.context import task_registry, ContextStackVars
22
- from kotonebot.backend.context.context import vars
23
- from kotonebot.client.host import Mumu12Host, LeidianHost
24
- from kotonebot.kaa.common import (
25
+ from kotonebot.kaa.config import (
25
26
  BaseConfig, APShopItems, CapsuleToysConfig, ClubRewardConfig, PurchaseConfig, ActivityFundsConfig,
26
27
  PresentsConfig, AssignmentConfig, ContestConfig, ProduceConfig,
27
28
  MissionRewardConfig, DailyMoneyShopItems, ProduceAction,
28
29
  RecommendCardDetectionMode, TraceConfig, StartGameConfig, EndGameConfig, UpgradeSupportCardConfig, MiscConfig,
29
30
  )
31
+ from kotonebot.kaa.config.produce import ProduceSolution, ProduceSolutionManager, ProduceData
30
32
 
31
33
  logger = logging.getLogger(__name__)
32
34
  GradioInput = gr.Textbox | gr.Number | gr.Checkbox | gr.Dropdown | gr.Radio | gr.Slider | gr.Tabs | gr.Tab
@@ -52,14 +54,7 @@ ConfigKey = Literal[
52
54
  'select_which_contestant',
53
55
 
54
56
  # produce
55
- 'produce_enabled', 'produce_mode',
56
- 'produce_count', 'produce_idols',
57
- 'memory_sets', 'auto_set_memory',
58
- 'auto_set_support', 'use_pt_boost',
59
- 'use_note_boost', 'follow_producer',
60
- 'self_study_lesson', 'prefer_lesson_ap',
61
- 'actions_order', 'recommend_card_detection_mode',
62
- 'use_ap_drink', 'skip_commu',
57
+ 'produce_enabled', 'selected_solution_id', 'produce_count',
63
58
  'mission_reward_enabled',
64
59
 
65
60
  # club reward
@@ -186,6 +181,15 @@ def _save_bug_report(
186
181
  zipf.write(file_path, arcname)
187
182
  yield f"### 打包 log 文件:{arcname}"
188
183
 
184
+ # 打包 conf 文件夹
185
+ if os.path.exists('conf'):
186
+ for root, dirs, files in os.walk('conf'):
187
+ for file in files:
188
+ file_path = os.path.join(root, file)
189
+ arcname = os.path.join('conf', os.path.relpath(file_path, 'conf'))
190
+ zipf.write(file_path, arcname)
191
+ yield f"### 打包配置文件:{arcname}"
192
+
189
193
  # 写出版本号
190
194
  zipf.writestr('version.txt', version)
191
195
 
@@ -387,14 +391,44 @@ class KotoneBotUI:
387
391
  """获取暂停按钮的状态和交互性"""
388
392
  try:
389
393
  text = "恢复" if vars.flow.is_paused else "暂停"
390
- except ValueError:
391
- # ValueError: Forwarded object vars called before initialization.
394
+ except ContextNotInitializedError:
395
+ # ContextNotInitializedError: Forwarded object vars called before initialization.
392
396
  # TODO: vars.flow.is_paused 应该要可以在脚本正式启动前就能访问
393
397
  text = '未启动'
394
398
  # 如果正在停止过程中,禁用暂停按钮
395
399
  interactive = not (self.is_stopping or self.is_single_task_stopping)
396
400
  return gr.Button(value=text, interactive=interactive)
397
401
 
402
+ def reload_config(self) -> bool:
403
+ """
404
+ 重新加载配置并重新初始化相关组件
405
+
406
+ :return: 是否成功重新加载
407
+ """
408
+ try:
409
+ # 重新加载配置文件
410
+ self._load_config()
411
+
412
+ # 重新设置 kaa 的配置
413
+ self._kaa.config_path = "config.json"
414
+ self._kaa.config_type = BaseConfig
415
+
416
+ # 重新初始化 kaa(这会重新创建设备和 Context)
417
+ self._setup_kaa()
418
+
419
+ # 重新加载 Context 中的配置数据
420
+ from kotonebot.backend.context.context import config
421
+ try:
422
+ config.load()
423
+ except ContextNotInitializedError:
424
+ pass
425
+
426
+ logger.info("配置已成功重新加载")
427
+ return True
428
+ except Exception as e:
429
+ logger.error(f"重新加载配置失败:{str(e)}")
430
+ return False
431
+
398
432
  def save_settings2(self, return_values: list[ConfigBuilderReturnValue], *args) -> str:
399
433
  options = BaseConfig()
400
434
  # return_values: (set_func, { 'key': component })
@@ -406,45 +440,50 @@ class KotoneBotUI:
406
440
  assert key in CONFIG_KEY_VALUE, f"未知的配置项:{key}"
407
441
  key = cast(ConfigKey, key)
408
442
  data[key] = value
409
-
443
+
410
444
  # 先设置options
411
445
  for (set_func, _) in return_values:
412
446
  set_func(options, data)
413
-
447
+
414
448
  # 验证规则1:截图方法验证
415
449
  screenshot_method = self.current_config.backend.screenshot_impl
416
450
  backend_type = self.current_config.backend.type
417
-
451
+
418
452
  valid_screenshot_methods = {
419
453
  'mumu12': ['adb', 'adb_raw', 'uiautomator2', 'nemu_ipc'],
420
454
  'leidian': ['adb', 'adb_raw', 'uiautomator2'],
421
455
  'custom': ['adb', 'adb_raw', 'uiautomator2'],
422
456
  'dmm': ['remote_windows', 'windows']
423
457
  }
424
-
458
+
425
459
  if screenshot_method not in valid_screenshot_methods.get(backend_type, []):
426
460
  gr.Warning(f"截图方法 '{screenshot_method}' 不适用于当前选择的模拟器类型,配置未保存。")
427
461
  return ""
428
-
429
- # 验证规则2:若启用培育,那么培育偶像不能为空
430
- if options.produce.enabled and not options.produce.idols:
431
- gr.Warning("启用培育时,培育偶像不能为空,配置未保存。")
462
+
463
+ # 验证规则2:若启用培育,那么必须选择培育方案
464
+ if options.produce.enabled and not options.produce.selected_solution_id:
465
+ gr.Warning("启用培育时,必须选择培育方案,配置未保存。")
432
466
  return ""
433
-
467
+
434
468
  # 验证规则3:若启用AP/金币购买,对应的商品不能为空
435
469
  if options.purchase.ap_enabled and not options.purchase.ap_items:
436
470
  gr.Warning("启用AP购买时,AP商店购买物品不能为空,配置未保存。")
437
471
  return ""
438
-
472
+
439
473
  if options.purchase.money_enabled and not options.purchase.money_items:
440
474
  gr.Warning("启用金币购买时,金币商店购买物品不能为空,配置未保存。")
441
475
  return ""
442
-
476
+
443
477
  # 验证通过,保存配置
444
478
  self.current_config.options = options
445
479
  try:
446
480
  save_config(self.config, "config.json")
447
- gr.Success("设置已保存,请重启程序!")
481
+
482
+ # 尝试热重载配置
483
+ if self.reload_config():
484
+ gr.Success("设置已保存并应用!")
485
+ else:
486
+ gr.Warning("设置已保存,但重新加载失败,请重启程序。")
448
487
  return ""
449
488
  except Exception as e:
450
489
  gr.Warning(f"保存设置失败:{str(e)}")
@@ -457,11 +496,76 @@ class KotoneBotUI:
457
496
  with gr.Row():
458
497
  run_btn = gr.Button("启动", scale=2)
459
498
  pause_btn = gr.Button("暂停", scale=1)
499
+
500
+ # 快速功能启停控制区域
501
+ gr.Markdown("### 快速功能启停")
502
+ with gr.Row(elem_classes=["quick-controls-row"]):
503
+ purchase_quick = gr.Checkbox(
504
+ label="商店",
505
+ value=self.current_config.options.purchase.enabled,
506
+ interactive=True,
507
+ elem_classes=["quick-checkbox"]
508
+ )
509
+ assignment_quick = gr.Checkbox(
510
+ label="工作",
511
+ value=self.current_config.options.assignment.enabled,
512
+ interactive=True,
513
+ elem_classes=["quick-checkbox"]
514
+ )
515
+ contest_quick = gr.Checkbox(
516
+ label="竞赛",
517
+ value=self.current_config.options.contest.enabled,
518
+ interactive=True,
519
+ elem_classes=["quick-checkbox"]
520
+ )
521
+ produce_quick = gr.Checkbox(
522
+ label="培育",
523
+ value=self.current_config.options.produce.enabled,
524
+ interactive=True,
525
+ elem_classes=["quick-checkbox"]
526
+ )
527
+ mission_reward_quick = gr.Checkbox(
528
+ label="任务",
529
+ value=self.current_config.options.mission_reward.enabled,
530
+ interactive=True,
531
+ elem_classes=["quick-checkbox"]
532
+ )
533
+ club_reward_quick = gr.Checkbox(
534
+ label="社团",
535
+ value=self.current_config.options.club_reward.enabled,
536
+ interactive=True,
537
+ elem_classes=["quick-checkbox"]
538
+ )
539
+ activity_funds_quick = gr.Checkbox(
540
+ label="活动费",
541
+ value=self.current_config.options.activity_funds.enabled,
542
+ interactive=True,
543
+ elem_classes=["quick-checkbox"]
544
+ )
545
+ presents_quick = gr.Checkbox(
546
+ label="礼物",
547
+ value=self.current_config.options.presents.enabled,
548
+ interactive=True,
549
+ elem_classes=["quick-checkbox"]
550
+ )
551
+ capsule_toys_quick = gr.Checkbox(
552
+ label="扭蛋",
553
+ value=self.current_config.options.capsule_toys.enabled,
554
+ interactive=True,
555
+ elem_classes=["quick-checkbox"]
556
+ )
557
+ upgrade_support_card_quick = gr.Checkbox(
558
+ label="支援卡",
559
+ value=self.current_config.options.upgrade_support_card.enabled,
560
+ interactive=True,
561
+ elem_classes=["quick-checkbox"]
562
+ )
563
+
460
564
  if self._kaa.upgrade_msg:
461
565
  gr.Markdown('### 配置升级报告')
462
566
  gr.Markdown(self._kaa.upgrade_msg)
463
567
  gr.Markdown('脚本报错或者卡住?前往"反馈"选项卡可以快速导出报告!')
464
-
568
+
465
569
  # 添加调试模式警告
466
570
  if self.current_config.keep_screenshots:
467
571
  gr.Markdown(
@@ -485,6 +589,45 @@ class KotoneBotUI:
485
589
  def on_pause_click(evt: gr.EventData) -> str:
486
590
  return self.toggle_pause()
487
591
 
592
+ # 快速功能控制的事件处理函数
593
+ def save_quick_setting(field_name: str, value: bool, display_name: str):
594
+ """保存快速设置并立即应用"""
595
+ try:
596
+ # 更新配置
597
+ if field_name == 'purchase':
598
+ self.current_config.options.purchase.enabled = value
599
+ elif field_name == 'assignment':
600
+ self.current_config.options.assignment.enabled = value
601
+ elif field_name == 'contest':
602
+ self.current_config.options.contest.enabled = value
603
+ elif field_name == 'produce':
604
+ self.current_config.options.produce.enabled = value
605
+ elif field_name == 'mission_reward':
606
+ self.current_config.options.mission_reward.enabled = value
607
+ elif field_name == 'club_reward':
608
+ self.current_config.options.club_reward.enabled = value
609
+ elif field_name == 'activity_funds':
610
+ self.current_config.options.activity_funds.enabled = value
611
+ elif field_name == 'presents':
612
+ self.current_config.options.presents.enabled = value
613
+ elif field_name == 'capsule_toys':
614
+ self.current_config.options.capsule_toys.enabled = value
615
+ elif field_name == 'upgrade_support_card':
616
+ self.current_config.options.upgrade_support_card.enabled = value
617
+ elif field_name == 'start_game':
618
+ self.current_config.options.start_game.enabled = value
619
+
620
+ # 保存配置
621
+ save_config(self.config, "config.json")
622
+
623
+ # 尝试热重载配置
624
+ if self.reload_config():
625
+ gr.Success(f"✓ {display_name} 已{'启用' if value else '禁用'}")
626
+ else:
627
+ gr.Warning(f"⚠ {display_name} 已保存,但重新加载失败")
628
+ except Exception as e:
629
+ gr.Error(f"✗ 保存失败:{str(e)}")
630
+
488
631
  run_btn.click(
489
632
  fn=on_run_click,
490
633
  outputs=[run_btn, task_status]
@@ -495,11 +638,68 @@ class KotoneBotUI:
495
638
  outputs=[pause_btn]
496
639
  )
497
640
 
641
+ # 绑定快速功能控制的事件
642
+ purchase_quick.change(
643
+ fn=lambda x: save_quick_setting('purchase', x, '商店'),
644
+ inputs=[purchase_quick]
645
+ )
646
+ assignment_quick.change(
647
+ fn=lambda x: save_quick_setting('assignment', x, '工作'),
648
+ inputs=[assignment_quick]
649
+ )
650
+ contest_quick.change(
651
+ fn=lambda x: save_quick_setting('contest', x, '竞赛'),
652
+ inputs=[contest_quick]
653
+ )
654
+ produce_quick.change(
655
+ fn=lambda x: save_quick_setting('produce', x, '培育'),
656
+ inputs=[produce_quick]
657
+ )
658
+ mission_reward_quick.change(
659
+ fn=lambda x: save_quick_setting('mission_reward', x, '任务奖励'),
660
+ inputs=[mission_reward_quick]
661
+ )
662
+ club_reward_quick.change(
663
+ fn=lambda x: save_quick_setting('club_reward', x, '社团奖励'),
664
+ inputs=[club_reward_quick]
665
+ )
666
+ activity_funds_quick.change(
667
+ fn=lambda x: save_quick_setting('activity_funds', x, '活动费'),
668
+ inputs=[activity_funds_quick]
669
+ )
670
+ presents_quick.change(
671
+ fn=lambda x: save_quick_setting('presents', x, '礼物'),
672
+ inputs=[presents_quick]
673
+ )
674
+ capsule_toys_quick.change(
675
+ fn=lambda x: save_quick_setting('capsule_toys', x, '扭蛋'),
676
+ inputs=[capsule_toys_quick]
677
+ )
678
+ upgrade_support_card_quick.change(
679
+ fn=lambda x: save_quick_setting('upgrade_support_card', x, '支援卡升级'),
680
+ inputs=[upgrade_support_card_quick]
681
+ )
682
+
498
683
  # 添加定时器,分别更新按钮状态和任务状态
499
684
  def update_run_button_status():
500
685
  text, interactive = self.get_button_status()
501
686
  return gr.Button(value=text, interactive=interactive)
502
687
 
688
+ def update_quick_checkboxes():
689
+ """更新快速功能控制的 checkbox 状态,确保与设置同步"""
690
+ return [
691
+ gr.Checkbox(value=self.current_config.options.purchase.enabled),
692
+ gr.Checkbox(value=self.current_config.options.assignment.enabled),
693
+ gr.Checkbox(value=self.current_config.options.contest.enabled),
694
+ gr.Checkbox(value=self.current_config.options.produce.enabled),
695
+ gr.Checkbox(value=self.current_config.options.mission_reward.enabled),
696
+ gr.Checkbox(value=self.current_config.options.club_reward.enabled),
697
+ gr.Checkbox(value=self.current_config.options.activity_funds.enabled),
698
+ gr.Checkbox(value=self.current_config.options.presents.enabled),
699
+ gr.Checkbox(value=self.current_config.options.capsule_toys.enabled),
700
+ gr.Checkbox(value=self.current_config.options.upgrade_support_card.enabled),
701
+ ]
702
+
503
703
  gr.Timer(1.0).tick(
504
704
  fn=update_run_button_status,
505
705
  outputs=[run_btn]
@@ -508,6 +708,14 @@ class KotoneBotUI:
508
708
  fn=self.get_pause_button_with_interactive,
509
709
  outputs=[pause_btn]
510
710
  )
711
+ gr.Timer(2.0).tick(
712
+ fn=update_quick_checkboxes,
713
+ outputs=[
714
+ purchase_quick, assignment_quick, contest_quick, produce_quick,
715
+ mission_reward_quick, club_reward_quick, activity_funds_quick, presents_quick,
716
+ capsule_toys_quick, upgrade_support_card_quick
717
+ ]
718
+ )
511
719
  gr.Timer(1.0).tick(
512
720
  fn=self.update_task_status,
513
721
  outputs=[task_status]
@@ -1029,13 +1237,21 @@ class KotoneBotUI:
1029
1237
  value=self.current_config.options.produce.enabled,
1030
1238
  info=ProduceConfig.model_fields['enabled'].description
1031
1239
  )
1240
+
1032
1241
  with gr.Group(visible=self.current_config.options.produce.enabled) as produce_group:
1033
- produce_mode = gr.Dropdown(
1034
- choices=["regular", "pro", "master"],
1035
- value=self.current_config.options.produce.mode,
1036
- label="培育模式",
1037
- info=ProduceConfig.model_fields['mode'].description
1242
+ # 培育方案管理区域
1243
+ solution_manager = ProduceSolutionManager()
1244
+ solutions = solution_manager.list()
1245
+ solution_choices = [(f"{sol.name} - {sol.description or '无描述'}", sol.id) for sol in solutions]
1246
+
1247
+ selected_solution_id = self.current_config.options.produce.selected_solution_id
1248
+ solution_dropdown = gr.Dropdown(
1249
+ choices=solution_choices,
1250
+ value=selected_solution_id,
1251
+ label="当前使用的培育方案",
1252
+ interactive=True
1038
1253
  )
1254
+
1039
1255
  produce_count = gr.Number(
1040
1256
  minimum=1,
1041
1257
  value=self.current_config.options.produce.produce_count,
@@ -1043,106 +1259,523 @@ class KotoneBotUI:
1043
1259
  interactive=True,
1044
1260
  info=ProduceConfig.model_fields['produce_count'].description
1045
1261
  )
1046
- # 添加偶像选择
1047
- idol_choices = []
1048
- for idol in IdolCard.all():
1049
- if idol.is_another:
1050
- idol_choices.append((f'{idol.name} 「{idol.another_name}」', idol.skin_id))
1051
- else:
1052
- idol_choices.append((f'{idol.name}', idol.skin_id))
1053
- selected_idols = self.current_config.options.produce.idols
1054
- produce_idols = gr.Dropdown(
1055
- choices=idol_choices,
1056
- value=selected_idols,
1057
- label="选择要培育的偶像",
1058
- multiselect=True,
1059
- interactive=True,
1060
- info=ProduceConfig.model_fields['idols'].description
1061
- )
1062
- has_kotone = any("藤田ことね" in idol for idol in selected_idols)
1063
- is_strict_mode = self.current_config.options.produce.recommend_card_detection_mode == RecommendCardDetectionMode.STRICT
1064
- kotone_warning = gr.Markdown(
1065
- visible=has_kotone and not is_strict_mode,
1066
- value="使用「藤田ことね」进行培育时,确保将「推荐卡检测模式」设置为「严格模式」"
1067
- )
1068
- auto_set_memory = gr.Checkbox(
1069
- label="自动编成回忆",
1070
- value=self.current_config.options.produce.auto_set_memory,
1071
- info=ProduceConfig.model_fields['auto_set_memory'].description
1072
- )
1073
- with gr.Group(visible=not self.current_config.options.produce.auto_set_memory) as memory_sets_group:
1074
- memory_sets = gr.Dropdown(
1075
- choices=[str(i) for i in range(1, 11)], # 假设最多10个编成位
1076
- value=[str(i) for i in self.current_config.options.produce.memory_sets],
1077
- label="回忆编成编号",
1262
+
1263
+ # 绑定启用状态变化事件
1264
+ def on_produce_enabled_change(enabled):
1265
+ return gr.Group(visible=enabled)
1266
+
1267
+ produce_enabled.change(
1268
+ fn=on_produce_enabled_change,
1269
+ inputs=[produce_enabled],
1270
+ outputs=[produce_group]
1271
+ )
1272
+
1273
+ # 存储设置Tab中的下拉框引用,供培育Tab使用
1274
+ self._settings_solution_dropdown = solution_dropdown
1275
+
1276
+ def set_config(config: BaseConfig, data: dict[ConfigKey, Any]) -> None:
1277
+ config.produce.enabled = data['produce_enabled']
1278
+ config.produce.selected_solution_id = data.get('selected_solution_id')
1279
+ config.produce.produce_count = data.get('produce_count', 1)
1280
+
1281
+ return set_config, {
1282
+ 'produce_enabled': produce_enabled,
1283
+ 'selected_solution_id': solution_dropdown,
1284
+ 'produce_count': produce_count
1285
+ }
1286
+
1287
+
1288
+ def _create_produce_tab(self) -> None:
1289
+ """创建培育Tab"""
1290
+ with gr.Tab("培育"):
1291
+ gr.Markdown("## 培育管理")
1292
+
1293
+ # 培育方案管理区域
1294
+ solution_manager = ProduceSolutionManager()
1295
+ solutions = solution_manager.list()
1296
+ solution_choices = [(f"{sol.name} - {sol.description or '无描述'}", sol.id) for sol in solutions]
1297
+
1298
+ selected_solution_id = self.current_config.options.produce.selected_solution_id
1299
+ solution_dropdown = gr.Dropdown(
1300
+ choices=solution_choices,
1301
+ value=selected_solution_id,
1302
+ label="选择培育方案",
1303
+ interactive=True
1304
+ )
1305
+
1306
+ # 获取设置Tab中的下拉框引用
1307
+ settings_dropdown = getattr(self, '_settings_solution_dropdown', None)
1308
+
1309
+ with gr.Row():
1310
+ new_solution_btn = gr.Button("新建培育", scale=1)
1311
+ delete_solution_btn = gr.Button("删除当前培育", scale=1)
1312
+
1313
+ # 培育方案详细设置区域
1314
+ with gr.Group() as solution_settings_group:
1315
+ # 获取当前选中的方案数据
1316
+ current_solution = None
1317
+ if selected_solution_id:
1318
+ try:
1319
+ current_solution = solution_manager.read(selected_solution_id)
1320
+ except FileNotFoundError:
1321
+ pass
1322
+
1323
+ if current_solution is None:
1324
+ # 如果没有选中方案,隐藏所有设置组件
1325
+ solution_name = gr.Textbox(label="方案名称", value="", visible=False)
1326
+ solution_description = gr.Textbox(label="方案描述", value="", visible=False)
1327
+ # 其他设置组件都设为不可见
1328
+ produce_mode = gr.Dropdown(
1329
+ choices=["regular", "pro", "master"],
1330
+ label="培育模式",
1331
+ info="进行一次 REGULAR 培育需要 ~30min,进行一次 PRO 培育需要 ~1h(具体视设备性能而定)。",
1332
+ visible=False
1333
+ )
1334
+ produce_count = gr.Number(
1335
+ minimum=1,
1336
+ label="培育次数",
1337
+ info="培育的次数。",
1338
+ visible=False
1339
+ )
1340
+
1341
+ # 添加偶像选择
1342
+ idol_choices = []
1343
+ for idol in IdolCard.all():
1344
+ if idol.is_another:
1345
+ idol_choices.append((f'{idol.name} 「{idol.another_name}」', idol.skin_id))
1346
+ else:
1347
+ idol_choices.append((f'{idol.name}', idol.skin_id))
1348
+
1349
+ produce_idols = gr.Dropdown(
1350
+ choices=idol_choices,
1351
+ label="选择要培育的偶像",
1352
+ multiselect=False,
1353
+ info="要培育偶像的 IdolCardSkin.id。",
1354
+ visible=False
1355
+ )
1356
+ kotone_warning = gr.Markdown(visible=False)
1357
+ auto_set_memory = gr.Checkbox(
1358
+ label="自动编成回忆",
1359
+ info="是否自动编成回忆。此选项优先级高于回忆编成编号。",
1360
+ visible=False
1361
+ )
1362
+ with gr.Group(visible=False) as memory_sets_group:
1363
+ memory_sets = gr.Dropdown(
1364
+ choices=[str(i) for i in range(1, 11)],
1365
+ label="回忆编成编号",
1366
+ multiselect=False,
1367
+ info="要使用的回忆编成编号,从 1 开始。",
1368
+ visible=False
1369
+ )
1370
+ auto_set_support = gr.Checkbox(
1371
+ label="自动编成支援卡",
1372
+ info="是否自动编成支援卡。此选项优先级高于支援卡编成编号。",
1373
+ visible=False
1374
+ )
1375
+ with gr.Group(visible=False) as support_card_sets_group:
1376
+ support_card_sets = gr.Dropdown(
1377
+ choices=[str(i) for i in range(1, 11)],
1378
+ label="支援卡编成编号",
1379
+ multiselect=False,
1380
+ info="要使用的支援卡编成编号,从 1 开始。",
1381
+ visible=False
1382
+ )
1383
+ use_pt_boost = gr.Checkbox(
1384
+ label="使用支援强化 Pt 提升",
1385
+ info="是否使用支援强化 Pt 提升。",
1386
+ visible=False
1387
+ )
1388
+ use_note_boost = gr.Checkbox(
1389
+ label="使用笔记数提升",
1390
+ info="是否使用笔记数提升。",
1391
+ visible=False
1392
+ )
1393
+ follow_producer = gr.Checkbox(
1394
+ label="关注租借了支援卡的制作人",
1395
+ info="是否关注租借了支援卡的制作人。",
1396
+ visible=False
1397
+ )
1398
+ self_study_lesson = gr.Dropdown(
1399
+ choices=['dance', 'visual', 'vocal'],
1400
+ label='文化课自习时选项',
1401
+ info='自习课类型。',
1402
+ visible=False
1403
+ )
1404
+ prefer_lesson_ap = gr.Checkbox(
1405
+ label="SP 课程优先",
1406
+ info="优先 SP 课程。启用后,若出现 SP 课程,则会优先执行 SP 课程,而不是推荐课程。若出现多个 SP 课程,随机选择一个。",
1407
+ visible=False
1408
+ )
1409
+ actions_order = gr.Dropdown(
1410
+ choices=[(action.display_name, action.value) for action in ProduceAction],
1411
+ label="行动优先级",
1412
+ info="每一周的行动将会按这里设置的优先级执行。",
1078
1413
  multiselect=True,
1414
+ visible=False
1415
+ )
1416
+ recommend_card_detection_mode = gr.Dropdown(
1417
+ choices=[
1418
+ (RecommendCardDetectionMode.NORMAL.display_name, RecommendCardDetectionMode.NORMAL.value),
1419
+ (RecommendCardDetectionMode.STRICT.display_name, RecommendCardDetectionMode.STRICT.value)
1420
+ ],
1421
+ label="推荐卡检测模式",
1422
+ info="推荐卡检测模式。严格模式下,识别速度会降低,但识别准确率会提高。",
1423
+ visible=False
1424
+ )
1425
+ use_ap_drink = gr.Checkbox(
1426
+ label="AP 不足时自动使用 AP 饮料",
1427
+ info="AP 不足时自动使用 AP 饮料",
1428
+ visible=False
1429
+ )
1430
+ skip_commu = gr.Checkbox(
1431
+ label="检测并跳过交流",
1432
+ info="检测并跳过交流",
1433
+ visible=False
1434
+ )
1435
+ save_solution_btn = gr.Button("保存培育方案", variant="primary", visible=False)
1436
+ else:
1437
+ # 显示选中方案的设置
1438
+ solution_name = gr.Textbox(
1439
+ label="方案名称",
1440
+ value=current_solution.name,
1441
+ interactive=True
1442
+ )
1443
+ solution_description = gr.Textbox(
1444
+ label="方案描述",
1445
+ value=current_solution.description or "",
1446
+ interactive=True
1447
+ )
1448
+
1449
+ produce_mode = gr.Dropdown(
1450
+ choices=["regular", "pro", "master"],
1451
+ value=current_solution.data.mode,
1452
+ label="培育模式",
1453
+ info="进行一次 REGULAR 培育需要 ~30min,进行一次 PRO 培育需要 ~1h(具体视设备性能而定)。"
1454
+ )
1455
+ produce_count = gr.Number(
1456
+ minimum=1,
1457
+ value=self.current_config.options.produce.produce_count,
1458
+ label="培育次数",
1079
1459
  interactive=True,
1080
- info=ProduceConfig.model_fields['memory_sets'].description
1460
+ info="培育的次数。"
1081
1461
  )
1082
1462
 
1083
- # 添加偶像选择变化时的回调
1084
- def update_kotone_warning(selected_idols, recommend_card_detection_mode):
1085
- has_kotone = any("藤田ことね" in idol for idol in selected_idols)
1086
- is_strict_mode = recommend_card_detection_mode == RecommendCardDetectionMode.STRICT.value
1087
- return gr.Markdown(visible=has_kotone and not is_strict_mode)
1463
+ # 添加偶像选择
1464
+ idol_choices = []
1465
+ for idol in IdolCard.all():
1466
+ if idol.is_another:
1467
+ idol_choices.append((f'{idol.name} 「{idol.another_name}」', idol.skin_id))
1468
+ else:
1469
+ idol_choices.append((f'{idol.name}', idol.skin_id))
1470
+
1471
+ produce_idols = gr.Dropdown(
1472
+ choices=idol_choices,
1473
+ value=current_solution.data.idol,
1474
+ label="选择要培育的偶像",
1475
+ multiselect=False,
1476
+ interactive=True,
1477
+ info="要培育偶像的 IdolCardSkin.id。"
1478
+ )
1088
1479
 
1089
- auto_set_support = gr.Checkbox(
1090
- label="自动编成支援卡",
1091
- value=self.current_config.options.produce.auto_set_support_card,
1092
- info=ProduceConfig.model_fields['auto_set_support_card'].description
1093
- )
1094
- use_pt_boost = gr.Checkbox(
1095
- label="使用支援强化 Pt 提升",
1096
- value=self.current_config.options.produce.use_pt_boost,
1097
- info=ProduceConfig.model_fields['use_pt_boost'].description
1098
- )
1099
- use_note_boost = gr.Checkbox(
1100
- label="使用笔记数提升",
1101
- value=self.current_config.options.produce.use_note_boost,
1102
- info=ProduceConfig.model_fields['use_note_boost'].description
1103
- )
1104
- follow_producer = gr.Checkbox(
1105
- label="关注租借了支援卡的制作人",
1106
- value=self.current_config.options.produce.follow_producer,
1107
- info=ProduceConfig.model_fields['follow_producer'].description
1108
- )
1109
- self_study_lesson = gr.Dropdown(
1110
- choices=['dance', 'visual', 'vocal'],
1111
- value=self.current_config.options.produce.self_study_lesson,
1112
- label='文化课自习时选项',
1113
- info='选择自习课类型'
1114
- )
1115
- prefer_lesson_ap = gr.Checkbox(
1116
- label="SP 课程优先",
1117
- value=self.current_config.options.produce.prefer_lesson_ap,
1118
- info=ProduceConfig.model_fields['prefer_lesson_ap'].description
1119
- )
1120
- actions_order = gr.Dropdown(
1121
- choices=[(action.display_name, action.value) for action in ProduceAction],
1122
- value=[action.value for action in self.current_config.options.produce.actions_order],
1123
- label="行动优先级",
1124
- info="设置每周行动的优先级顺序",
1125
- multiselect=True
1126
- )
1127
- recommend_card_detection_mode = gr.Dropdown(
1128
- choices=[
1129
- (RecommendCardDetectionMode.NORMAL.display_name, RecommendCardDetectionMode.NORMAL.value),
1130
- (RecommendCardDetectionMode.STRICT.display_name, RecommendCardDetectionMode.STRICT.value)
1131
- ],
1132
- value=self.current_config.options.produce.recommend_card_detection_mode.value,
1133
- label="推荐卡检测模式",
1134
- info=ProduceConfig.model_fields['recommend_card_detection_mode'].description
1135
- )
1136
- use_ap_drink = gr.Checkbox(
1137
- label="AP 不足时自动使用 AP 饮料",
1138
- value=self.current_config.options.produce.use_ap_drink,
1139
- info=ProduceConfig.model_fields['use_ap_drink'].description
1140
- )
1141
- skip_commu = gr.Checkbox(
1142
- label="检测并跳过交流",
1143
- value=self.current_config.options.produce.skip_commu,
1144
- info=ProduceConfig.model_fields['skip_commu'].description
1145
- )
1480
+ has_kotone = bool(current_solution.data.idol and "藤田ことね" in current_solution.data.idol)
1481
+ is_strict_mode = current_solution.data.recommend_card_detection_mode == RecommendCardDetectionMode.STRICT
1482
+ kotone_warning = gr.Markdown(
1483
+ visible=has_kotone and not is_strict_mode,
1484
+ value="使用「藤田ことね」进行培育时,确保将「推荐卡检测模式」设置为「严格模式」"
1485
+ )
1486
+
1487
+ auto_set_memory = gr.Checkbox(
1488
+ label="自动编成回忆",
1489
+ value=current_solution.data.auto_set_memory,
1490
+ info="是否自动编成回忆。此选项优先级高于回忆编成编号。"
1491
+ )
1492
+
1493
+ with gr.Group(visible=not current_solution.data.auto_set_memory) as memory_sets_group:
1494
+ memory_sets = gr.Dropdown(
1495
+ choices=[str(i) for i in range(1, 11)], # 假设最多10个编成位
1496
+ value=str(current_solution.data.memory_set) if current_solution.data.memory_set else None,
1497
+ label="回忆编成编号",
1498
+ multiselect=False,
1499
+ interactive=True,
1500
+ info="要使用的回忆编成编号,从 1 开始。"
1501
+ )
1502
+
1503
+ auto_set_support = gr.Checkbox(
1504
+ label="自动编成支援卡",
1505
+ value=current_solution.data.auto_set_support_card,
1506
+ info="是否自动编成支援卡。此选项优先级高于支援卡编成编号。"
1507
+ )
1508
+
1509
+ with gr.Group(visible=not current_solution.data.auto_set_support_card) as support_card_sets_group:
1510
+ support_card_sets = gr.Dropdown(
1511
+ choices=[str(i) for i in range(1, 11)], # 假设最多10个编成位
1512
+ value=str(current_solution.data.support_card_set) if current_solution.data.support_card_set else None,
1513
+ label="支援卡编成编号",
1514
+ multiselect=False,
1515
+ interactive=True,
1516
+ info="要使用的支援卡编成编号,从 1 开始。"
1517
+ )
1518
+ use_pt_boost = gr.Checkbox(
1519
+ label="使用支援强化 Pt 提升",
1520
+ value=current_solution.data.use_pt_boost,
1521
+ info="是否使用支援强化 Pt 提升。"
1522
+ )
1523
+ use_note_boost = gr.Checkbox(
1524
+ label="使用笔记数提升",
1525
+ value=current_solution.data.use_note_boost,
1526
+ info="是否使用笔记数提升。"
1527
+ )
1528
+ follow_producer = gr.Checkbox(
1529
+ label="关注租借了支援卡的制作人",
1530
+ value=current_solution.data.follow_producer,
1531
+ info="是否关注租借了支援卡的制作人。"
1532
+ )
1533
+ self_study_lesson = gr.Dropdown(
1534
+ choices=['dance', 'visual', 'vocal'],
1535
+ value=current_solution.data.self_study_lesson,
1536
+ label='文化课自习时选项',
1537
+ info='自习课类型。'
1538
+ )
1539
+ prefer_lesson_ap = gr.Checkbox(
1540
+ label="SP 课程优先",
1541
+ value=current_solution.data.prefer_lesson_ap,
1542
+ info="优先 SP 课程。启用后,若出现 SP 课程,则会优先执行 SP 课程,而不是推荐课程。若出现多个 SP 课程,随机选择一个。"
1543
+ )
1544
+ actions_order = gr.Dropdown(
1545
+ choices=[(action.display_name, action.value) for action in ProduceAction],
1546
+ value=[action.value for action in current_solution.data.actions_order],
1547
+ label="行动优先级",
1548
+ info="每一周的行动将会按这里设置的优先级执行。",
1549
+ multiselect=True
1550
+ )
1551
+ recommend_card_detection_mode = gr.Dropdown(
1552
+ choices=[
1553
+ (RecommendCardDetectionMode.NORMAL.display_name, RecommendCardDetectionMode.NORMAL.value),
1554
+ (RecommendCardDetectionMode.STRICT.display_name, RecommendCardDetectionMode.STRICT.value)
1555
+ ],
1556
+ value=current_solution.data.recommend_card_detection_mode.value,
1557
+ label="推荐卡检测模式",
1558
+ info="推荐卡检测模式。严格模式下,识别速度会降低,但识别准确率会提高。"
1559
+ )
1560
+ use_ap_drink = gr.Checkbox(
1561
+ label="AP 不足时自动使用 AP 饮料",
1562
+ value=current_solution.data.use_ap_drink,
1563
+ info="AP 不足时自动使用 AP 饮料"
1564
+ )
1565
+ skip_commu = gr.Checkbox(
1566
+ label="检测并跳过交流",
1567
+ value=current_solution.data.skip_commu,
1568
+ info="检测并跳过交流"
1569
+ )
1570
+
1571
+ # 添加保存按钮
1572
+ save_solution_btn = gr.Button("保存培育方案", variant="primary")
1573
+
1574
+ # 添加事件处理
1575
+ def update_kotone_warning(selected_idol, recommend_card_detection_mode):
1576
+ # Handle case where selected_idol is None (no selection)
1577
+ # selected_idol is a single string (skin_id), not a list
1578
+ if selected_idol is None:
1579
+ has_kotone = False
1580
+ else:
1581
+ has_kotone = "藤田ことね" in selected_idol
1582
+ is_strict_mode = recommend_card_detection_mode == RecommendCardDetectionMode.STRICT.value
1583
+ return gr.Markdown(visible=has_kotone and not is_strict_mode)
1584
+
1585
+ def on_solution_change(solution_id):
1586
+ """当选择的培育方案改变时,更新所有设置组件"""
1587
+ if not solution_id:
1588
+ return [
1589
+ gr.Textbox(value="", visible=False), # solution_name
1590
+ gr.Textbox(value="", visible=False), # solution_description
1591
+ gr.Dropdown(visible=False), # produce_mode
1592
+ gr.Number(visible=False), # produce_count
1593
+ gr.Dropdown(visible=False), # produce_idols
1594
+ gr.Markdown(visible=False), # kotone_warning
1595
+ gr.Checkbox(visible=False), # auto_set_memory
1596
+ gr.Group(visible=False), # memory_sets_group
1597
+ gr.Dropdown(visible=False), # memory_sets
1598
+ gr.Checkbox(visible=False), # auto_set_support
1599
+ gr.Checkbox(visible=False), # use_pt_boost
1600
+ gr.Checkbox(visible=False), # use_note_boost
1601
+ gr.Checkbox(visible=False), # follow_producer
1602
+ gr.Dropdown(visible=False), # self_study_lesson
1603
+ gr.Checkbox(visible=False), # prefer_lesson_ap
1604
+ gr.Dropdown(visible=False), # actions_order
1605
+ gr.Dropdown(visible=False), # recommend_card_detection_mode
1606
+ gr.Checkbox(visible=False), # use_ap_drink
1607
+ gr.Checkbox(visible=False), # skip_commu
1608
+ gr.Button(visible=False), # save_solution_btn
1609
+ ]
1610
+
1611
+ try:
1612
+ solution = solution_manager.read(solution_id)
1613
+ has_kotone = bool(solution.data.idol and "藤田ことね" in solution.data.idol)
1614
+ is_strict_mode = solution.data.recommend_card_detection_mode == RecommendCardDetectionMode.STRICT
1615
+
1616
+ return [
1617
+ gr.Textbox(value=solution.name, visible=True),
1618
+ gr.Textbox(value=solution.description or "", visible=True),
1619
+ gr.Dropdown(value=solution.data.mode, visible=True),
1620
+ gr.Number(value=self.current_config.options.produce.produce_count, visible=True),
1621
+ gr.Dropdown(value=solution.data.idol, visible=True),
1622
+ gr.Markdown(visible=has_kotone and not is_strict_mode),
1623
+ gr.Checkbox(value=solution.data.auto_set_memory, visible=True),
1624
+ gr.Group(visible=not solution.data.auto_set_memory),
1625
+ gr.Dropdown(value=str(solution.data.memory_set) if solution.data.memory_set else None, visible=True),
1626
+ gr.Checkbox(value=solution.data.auto_set_support_card, visible=True),
1627
+ gr.Group(visible=not solution.data.auto_set_support_card),
1628
+ gr.Dropdown(value=str(solution.data.support_card_set) if solution.data.support_card_set else None, visible=True),
1629
+ gr.Checkbox(value=solution.data.use_pt_boost, visible=True),
1630
+ gr.Checkbox(value=solution.data.use_note_boost, visible=True),
1631
+ gr.Checkbox(value=solution.data.follow_producer, visible=True),
1632
+ gr.Dropdown(value=solution.data.self_study_lesson, visible=True),
1633
+ gr.Checkbox(value=solution.data.prefer_lesson_ap, visible=True),
1634
+ gr.Dropdown(value=[action.value for action in solution.data.actions_order], visible=True),
1635
+ gr.Dropdown(value=solution.data.recommend_card_detection_mode.value, visible=True),
1636
+ gr.Checkbox(value=solution.data.use_ap_drink, visible=True),
1637
+ gr.Checkbox(value=solution.data.skip_commu, visible=True),
1638
+ gr.Button(visible=True), # save_solution_btn
1639
+ ]
1640
+ except FileNotFoundError:
1641
+ gr.Warning(f"培育方案 {solution_id} 不存在")
1642
+ return on_solution_change(None)
1643
+ except Exception as e:
1644
+ gr.Error(f"加载培育方案失败:{str(e)}")
1645
+ return on_solution_change(None)
1646
+
1647
+ def on_new_solution():
1648
+ """创建新的培育方案"""
1649
+ try:
1650
+ new_solution = solution_manager.new("新培育方案")
1651
+ solution_manager.save(new_solution.id, new_solution)
1652
+
1653
+ # 重新列出所有方案
1654
+ solutions = solution_manager.list()
1655
+ solution_choices = [(f"{sol.name} - {sol.description or '无描述'}", sol.id) for sol in solutions]
1656
+
1657
+ gr.Success("新培育方案创建成功")
1658
+ # 根据是否有设置Tab的下拉框来决定返回值
1659
+ updated_dropdown = gr.Dropdown(choices=solution_choices, value=new_solution.id)
1660
+ if settings_dropdown is not None:
1661
+ return [updated_dropdown, updated_dropdown]
1662
+ else:
1663
+ return updated_dropdown
1664
+ except Exception as e:
1665
+ gr.Error(f"创建培育方案失败:{str(e)}")
1666
+ if settings_dropdown is not None:
1667
+ return [gr.Dropdown(), gr.Dropdown()]
1668
+ else:
1669
+ return gr.Dropdown()
1670
+
1671
+ def on_delete_solution(solution_id):
1672
+ """删除当前培育方案"""
1673
+ if not solution_id:
1674
+ gr.Warning("请先选择要删除的培育方案")
1675
+ if settings_dropdown is not None:
1676
+ return [gr.Dropdown(), gr.Dropdown()]
1677
+ else:
1678
+ return gr.Dropdown()
1679
+
1680
+ try:
1681
+ solution_manager.delete(solution_id)
1682
+
1683
+ # 重新列出所有方案
1684
+ solutions = solution_manager.list()
1685
+ solution_choices = [(f"{sol.name} - {sol.description or '无描述'}", sol.id) for sol in solutions]
1686
+
1687
+ gr.Success("培育方案删除成功")
1688
+ # 根据是否有设置Tab的下拉框来决定返回值
1689
+ updated_dropdown = gr.Dropdown(choices=solution_choices, value=None)
1690
+ if settings_dropdown is not None:
1691
+ return [updated_dropdown, updated_dropdown]
1692
+ else:
1693
+ return updated_dropdown
1694
+ except Exception as e:
1695
+ gr.Error(f"删除培育方案失败:{str(e)}")
1696
+ if settings_dropdown is not None:
1697
+ return [gr.Dropdown(), gr.Dropdown()]
1698
+ else:
1699
+ return gr.Dropdown()
1700
+
1701
+ def on_save_solution(solution_id, name, description, mode, count, idols, auto_memory, memory_sets,
1702
+ auto_support, support_card_sets, pt_boost, note_boost, follow_producer, study_lesson, prefer_ap,
1703
+ actions, detection_mode, ap_drink, skip_commu_val):
1704
+ """保存培育方案"""
1705
+ if not solution_id:
1706
+ gr.Warning("请先选择要保存的培育方案")
1707
+ if settings_dropdown is not None:
1708
+ return [gr.Dropdown(), gr.Dropdown()]
1709
+ else:
1710
+ return gr.Dropdown()
1711
+
1712
+ try:
1713
+ # 构建培育数据
1714
+ produce_data = ProduceData(
1715
+ mode=mode,
1716
+ idol=idols if idols else None,
1717
+ memory_set=int(memory_sets) if memory_sets else None,
1718
+ support_card_set=int(support_card_sets) if support_card_sets else None,
1719
+ auto_set_memory=auto_memory,
1720
+ auto_set_support_card=auto_support,
1721
+ use_pt_boost=pt_boost,
1722
+ use_note_boost=note_boost,
1723
+ follow_producer=follow_producer,
1724
+ self_study_lesson=study_lesson,
1725
+ prefer_lesson_ap=prefer_ap,
1726
+ actions_order=[ProduceAction(action) for action in actions] if actions else [],
1727
+ recommend_card_detection_mode=RecommendCardDetectionMode(detection_mode),
1728
+ use_ap_drink=ap_drink,
1729
+ skip_commu=skip_commu_val
1730
+ )
1731
+
1732
+ # 构建方案对象
1733
+ solution = ProduceSolution(
1734
+ id=solution_id,
1735
+ name=name or "未命名方案",
1736
+ description=description,
1737
+ data=produce_data
1738
+ )
1739
+
1740
+ # 保存方案
1741
+ solution_manager.save(solution_id, solution)
1742
+
1743
+ # 同时更新配置中的 produce_count
1744
+ self.current_config.options.produce.produce_count = int(count)
1745
+
1746
+ # 重新列出所有方案(确保没有重复项)
1747
+ solutions = solution_manager.list()
1748
+ solution_choices = [(f"{sol.name} - {sol.description or '无描述'}", sol.id) for sol in solutions]
1749
+
1750
+ gr.Success("培育方案保存成功")
1751
+ # 根据是否有设置Tab的下拉框来决定返回值
1752
+ updated_dropdown = gr.Dropdown(choices=solution_choices, value=solution_id)
1753
+ if settings_dropdown is not None:
1754
+ return [updated_dropdown, updated_dropdown]
1755
+ else:
1756
+ return updated_dropdown
1757
+ except Exception as e:
1758
+ gr.Error(f"保存培育方案失败:{str(e)}")
1759
+ if settings_dropdown is not None:
1760
+ return [gr.Dropdown(), gr.Dropdown()]
1761
+ else:
1762
+ return gr.Dropdown()
1763
+
1764
+ # 绑定事件
1765
+ # 为所有控件绑定change事件,无论是否有选中方案
1766
+ auto_set_memory.change(
1767
+ fn=lambda x: gr.Group(visible=not x),
1768
+ inputs=[auto_set_memory],
1769
+ outputs=[memory_sets_group]
1770
+ )
1771
+
1772
+ auto_set_support.change(
1773
+ fn=lambda x: gr.Group(visible=not x),
1774
+ inputs=[auto_set_support],
1775
+ outputs=[support_card_sets_group]
1776
+ )
1777
+
1778
+ if current_solution is not None:
1146
1779
  recommend_card_detection_mode.change(
1147
1780
  fn=update_kotone_warning,
1148
1781
  inputs=[produce_idols, recommend_card_detection_mode],
@@ -1154,54 +1787,56 @@ class KotoneBotUI:
1154
1787
  outputs=kotone_warning
1155
1788
  )
1156
1789
 
1157
- produce_enabled.change(
1158
- fn=lambda x: gr.Group(visible=x),
1159
- inputs=[produce_enabled],
1160
- outputs=[produce_group]
1790
+ # 绑定方案管理事件
1791
+ solution_dropdown.change(
1792
+ fn=on_solution_change,
1793
+ inputs=[solution_dropdown],
1794
+ outputs=[
1795
+ solution_name, solution_description,
1796
+ produce_mode, produce_count, produce_idols, kotone_warning,
1797
+ auto_set_memory, memory_sets_group, memory_sets,
1798
+ auto_set_support, support_card_sets_group, support_card_sets,
1799
+ use_pt_boost, use_note_boost, follow_producer,
1800
+ self_study_lesson, prefer_lesson_ap, actions_order,
1801
+ recommend_card_detection_mode, use_ap_drink, skip_commu,
1802
+ save_solution_btn
1803
+ ]
1161
1804
  )
1162
1805
 
1163
- auto_set_memory.change(
1164
- fn=lambda x: gr.Group(visible=not x),
1165
- inputs=[auto_set_memory],
1166
- outputs=[memory_sets_group]
1806
+ # 准备输出列表,如果设置Tab的下拉框存在,则同时更新
1807
+ outputs_for_new = [solution_dropdown]
1808
+ outputs_for_delete = [solution_dropdown]
1809
+ outputs_for_save = [solution_dropdown]
1810
+
1811
+ if settings_dropdown is not None:
1812
+ outputs_for_new.append(settings_dropdown)
1813
+ outputs_for_delete.append(settings_dropdown)
1814
+ outputs_for_save.append(settings_dropdown)
1815
+
1816
+ new_solution_btn.click(
1817
+ fn=on_new_solution,
1818
+ outputs=outputs_for_new
1819
+ )
1820
+
1821
+ delete_solution_btn.click(
1822
+ fn=on_delete_solution,
1823
+ inputs=[solution_dropdown],
1824
+ outputs=outputs_for_delete
1825
+ )
1826
+
1827
+ # 绑定保存按钮事件
1828
+ save_solution_btn.click(
1829
+ fn=on_save_solution,
1830
+ inputs=[
1831
+ solution_dropdown, solution_name, solution_description,
1832
+ produce_mode, produce_count, produce_idols,
1833
+ auto_set_memory, memory_sets, auto_set_support, support_card_sets,
1834
+ use_pt_boost, use_note_boost, follow_producer,
1835
+ self_study_lesson, prefer_lesson_ap, actions_order,
1836
+ recommend_card_detection_mode, use_ap_drink, skip_commu
1837
+ ],
1838
+ outputs=outputs_for_save
1167
1839
  )
1168
-
1169
- def set_config(config: BaseConfig, data: dict[ConfigKey, Any]) -> None:
1170
- config.produce.enabled = data['produce_enabled']
1171
- config.produce.mode = data['produce_mode']
1172
- config.produce.produce_count = data['produce_count']
1173
- config.produce.idols = data['produce_idols']
1174
- config.produce.memory_sets = [int(i) for i in data['memory_sets']]
1175
- config.produce.auto_set_memory = data['auto_set_memory']
1176
- config.produce.auto_set_support_card = data['auto_set_support']
1177
- config.produce.use_pt_boost = data['use_pt_boost']
1178
- config.produce.use_note_boost = data['use_note_boost']
1179
- config.produce.follow_producer = data['follow_producer']
1180
- config.produce.self_study_lesson = data['self_study_lesson']
1181
- config.produce.prefer_lesson_ap = data['prefer_lesson_ap']
1182
- config.produce.actions_order = [ProduceAction(action) for action in data['actions_order']]
1183
- config.produce.recommend_card_detection_mode = RecommendCardDetectionMode(data['recommend_card_detection_mode'])
1184
- config.produce.use_ap_drink = data['use_ap_drink']
1185
- config.produce.skip_commu = data['skip_commu']
1186
-
1187
- return set_config, {
1188
- 'produce_enabled': produce_enabled,
1189
- 'produce_mode': produce_mode,
1190
- 'produce_count': produce_count,
1191
- 'produce_idols': produce_idols,
1192
- 'memory_sets': memory_sets,
1193
- 'auto_set_memory': auto_set_memory,
1194
- 'auto_set_support': auto_set_support,
1195
- 'use_pt_boost': use_pt_boost,
1196
- 'use_note_boost': use_note_boost,
1197
- 'follow_producer': follow_producer,
1198
- 'self_study_lesson': self_study_lesson,
1199
- 'prefer_lesson_ap': prefer_lesson_ap,
1200
- 'actions_order': actions_order,
1201
- 'recommend_card_detection_mode': recommend_card_detection_mode,
1202
- 'use_ap_drink': use_ap_drink,
1203
- 'skip_commu': skip_commu
1204
- }
1205
1840
 
1206
1841
  def _create_club_reward_settings(self) -> ConfigBuilderReturnValue:
1207
1842
  with gr.Column():
@@ -1897,7 +2532,20 @@ class KotoneBotUI:
1897
2532
  self.current_config = self.config.user_configs[0]
1898
2533
 
1899
2534
  def create_ui(self) -> gr.Blocks:
1900
- with gr.Blocks(title="琴音小助手", css="#container { max-width: 800px; margin: auto; padding: 20px; }") as app:
2535
+ custom_css = """
2536
+ #container { max-width: 800px; margin: auto; padding: 20px; }
2537
+ .quick-controls-row > div {
2538
+ display: flex !important;
2539
+ flex-wrap: nowrap !important;
2540
+ gap: 0 !important;
2541
+ overflow-x: auto !important;
2542
+ }
2543
+ .quick-controls-row > div > div {
2544
+ min-width: auto !important;
2545
+ padding: 0;
2546
+ }
2547
+ """
2548
+ with gr.Blocks(title="琴音小助手", css=custom_css) as app:
1901
2549
  with gr.Column(elem_id="container"):
1902
2550
  gr.Markdown(f"# 琴音小助手 v{self._kaa.version}")
1903
2551
 
@@ -1905,6 +2553,7 @@ class KotoneBotUI:
1905
2553
  self._create_status_tab()
1906
2554
  self._create_task_tab()
1907
2555
  self._create_settings_tab()
2556
+ self._create_produce_tab()
1908
2557
  self._create_log_tab()
1909
2558
  self._create_whats_new_tab()
1910
2559
  self._create_screen_tab()