ksaa 2025.11b1__py3-none-any.whl → 2025.11b3__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 (323) hide show
  1. kaa/application/core/feedback_service.py +121 -0
  2. kaa/application/core/misc_core.py +4 -1
  3. kaa/application/core/update_service.py +208 -0
  4. kaa/config/schema.py +6 -0
  5. kaa/errors.py +60 -0
  6. kaa/main/gr.py +106 -516
  7. kaa/main/kaa.py +11 -3
  8. kaa/metadata.py +10 -0
  9. kaa/resources/__pycache__/__init__.cpython-310.pyc +0 -0
  10. kaa/resources/game.db +0 -0
  11. kaa/resources/game_ver.txt +0 -0
  12. kaa/resources/idol_cards/i_card-skin-amao-3-014_1.png +0 -0
  13. kaa/resources/idol_cards/i_card-skin-amao-3-015_0.png +0 -0
  14. kaa/resources/idol_cards/i_card-skin-atbm-1-000_0.png +0 -0
  15. kaa/resources/idol_cards/i_card-skin-atbm-1-000_1.png +0 -0
  16. kaa/resources/idol_cards/i_card-skin-atbm-2-000_0.png +0 -0
  17. kaa/resources/idol_cards/i_card-skin-atbm-2-000_1.png +0 -0
  18. kaa/resources/idol_cards/i_card-skin-atbm-3-000_0.png +0 -0
  19. kaa/resources/idol_cards/i_card-skin-atbm-3-000_1.png +0 -0
  20. kaa/resources/idol_cards/i_card-skin-fktn-3-016_0.png +0 -0
  21. kaa/resources/idol_cards/i_card-skin-fktn-3-016_1.png +0 -0
  22. kaa/resources/idol_cards/i_card-skin-hmsz-3-003_0.png +0 -0
  23. kaa/resources/idol_cards/i_card-skin-hmsz-3-003_1.png +0 -0
  24. kaa/resources/idol_cards/i_card-skin-hmsz-3-009_0.png +0 -0
  25. kaa/resources/idol_cards/i_card-skin-hmsz-3-009_1.png +0 -0
  26. kaa/resources/idol_cards/i_card-skin-hmsz-3-013_0.png +0 -0
  27. kaa/resources/idol_cards/i_card-skin-hmsz-3-013_1.png +0 -0
  28. kaa/resources/idol_cards/i_card-skin-hrnm-3-015_0.png +0 -0
  29. kaa/resources/idol_cards/i_card-skin-hrnm-3-015_1.png +0 -0
  30. kaa/resources/idol_cards/i_card-skin-hski-3-015_0.png +0 -0
  31. kaa/resources/idol_cards/i_card-skin-hski-3-015_1.png +0 -0
  32. kaa/resources/idol_cards/i_card-skin-hume-3-009_0.png +0 -0
  33. kaa/resources/idol_cards/i_card-skin-hume-3-009_1.png +0 -0
  34. kaa/resources/idol_cards/i_card-skin-hume-3-015_0.png +0 -0
  35. kaa/resources/idol_cards/i_card-skin-hume-3-015_1.png +0 -0
  36. kaa/resources/idol_cards/i_card-skin-jsna-3-009_0.png +0 -0
  37. kaa/resources/idol_cards/i_card-skin-jsna-3-009_1.png +0 -0
  38. kaa/resources/idol_cards/i_card-skin-jsna-3-014_0.png +0 -0
  39. kaa/resources/idol_cards/i_card-skin-jsna-3-014_1.png +0 -0
  40. kaa/resources/idol_cards/i_card-skin-kcna-3-014_1.png +0 -0
  41. kaa/resources/idol_cards/i_card-skin-kcna-3-015_0.png +0 -0
  42. kaa/resources/idol_cards/i_card-skin-kcna-3-015_1.png +0 -0
  43. kaa/resources/idol_cards/i_card-skin-kllj-3-014_0.png +0 -0
  44. kaa/resources/idol_cards/i_card-skin-kllj-3-014_1.png +0 -0
  45. kaa/resources/idol_cards/i_card-skin-shro-3-015_0.png +0 -0
  46. kaa/resources/idol_cards/i_card-skin-shro-3-015_1.png +0 -0
  47. kaa/resources/idol_cards/i_card-skin-ssmk-3-015_0.png +0 -0
  48. kaa/resources/idol_cards/i_card-skin-ssmk-3-015_1.png +0 -0
  49. kaa/resources/idol_cards/i_card-skin-ttmr-3-015_0.png +0 -0
  50. kaa/resources/idol_cards/i_card-skin-ttmr-3-015_1.png +0 -0
  51. kaa/sprites/19513e9f-2cbb-4f66-84b7-2ad2faed252d.png +0 -0
  52. kaa/sprites/1ef5fa52-b6e1-42d0-947a-ce970eba057d.png +0 -0
  53. kaa/sprites/318abb8a-5950-4d22-ac42-77219b5bc1a0.png +0 -0
  54. kaa/sprites/321b7040-87d7-4f87-9b44-ad2972584a11.png +0 -0
  55. kaa/sprites/3ae72684-1d40-43cf-9508-511c010de64f.png +0 -0
  56. kaa/sprites/3e669188-5933-4502-b039-38f4d4649664.png +0 -0
  57. kaa/sprites/4370013d-f052-4314-94ff-a342d70754c3.png +0 -0
  58. kaa/sprites/4fb1d36c-5fb6-4fe5-9ba3-07e056eb1dfc.png +0 -0
  59. kaa/sprites/5247b052-5b45-4e64-b7fc-d566f5d4bc82.png +0 -0
  60. kaa/sprites/545a9032-a676-4d9d-ac74-2b2c9b330d1a.png +0 -0
  61. kaa/sprites/57741798-65dd-47eb-b4b1-b3f0e3c3e318.png +0 -0
  62. kaa/sprites/5e2b4bb9-f200-4723-96ac-5f907e28eaaa.png +0 -0
  63. kaa/sprites/5f6fafd9-43aa-443e-994e-f2688af5e238.png +0 -0
  64. kaa/sprites/61229c71-303b-4dc9-ba4e-6a14e5ab161e.png +0 -0
  65. kaa/sprites/62f93327-5946-4a48-aff8-a203483b0562.png +0 -0
  66. kaa/sprites/64dfeb35-61ad-4e9b-9847-a18530f02584.png +0 -0
  67. kaa/sprites/64f8ef99-4766-471b-aeb0-b109704d9615.png +0 -0
  68. kaa/sprites/677933e9-1481-4f01-95b4-d55bea51db8c.png +0 -0
  69. kaa/sprites/67edcd91-d2c1-418b-987a-e60263626f56.png +0 -0
  70. kaa/sprites/6c032aa7-20e3-4e2e-b1a4-1585141ba22b.png +0 -0
  71. kaa/sprites/6fadb00b-e32e-4c45-a738-f21b8f48c139.png +0 -0
  72. kaa/sprites/719297ec-82be-4820-8ecf-8bf6322b81fe.png +0 -0
  73. kaa/sprites/76970b91-7864-4413-bfc7-79c04a48dce7.png +0 -0
  74. kaa/sprites/7c62081d-097a-4514-a69d-69e96201e816.png +0 -0
  75. kaa/sprites/7e16af89-bb51-4889-8a7e-25715ff5faa1.png +0 -0
  76. kaa/sprites/7efce7bc-12a5-4a53-9a0a-9fa755649ebd.png +0 -0
  77. kaa/sprites/803fb770-6982-4460-8fe0-f9ccd67367c2.png +0 -0
  78. kaa/sprites/82200c8c-0916-4601-839a-945f96cc4ebc.png +0 -0
  79. kaa/sprites/8299e3e2-cfd5-4380-adce-a46c93b1be4d.png +0 -0
  80. kaa/sprites/83c27159-36d2-4ccf-ace7-e5d2169e7e52.png +0 -0
  81. kaa/sprites/8661bc83-9b0a-4555-8b21-2258b31c7f57.png +0 -0
  82. kaa/sprites/89437aca-7339-4795-b848-ec529b1e5e8d.png +0 -0
  83. kaa/sprites/8a0260f5-b32e-430e-bc98-7b5a77cab6ab.png +0 -0
  84. kaa/sprites/8c3bc157-022a-4bb1-be74-af1ad254e67f.png +0 -0
  85. kaa/sprites/8d09178a-251e-4f74-b023-12233417621b.png +0 -0
  86. kaa/sprites/8fbee6fe-9409-407e-8f55-d2d36ab37f6a.png +0 -0
  87. kaa/sprites/8fdc102b-d8f3-4d16-b8ef-1d804f5aff07.png +0 -0
  88. kaa/sprites/93e91dd0-0050-48b4-8bf8-c732cd76f0e3.png +0 -0
  89. kaa/sprites/993a33ac-994b-4eb0-9c1e-b9412d499d67.png +0 -0
  90. kaa/sprites/99a27ff1-bc1c-48a2-9f9b-0803338d1bd8.png +0 -0
  91. kaa/sprites/9a9a1f40-d308-4aa5-8d91-60342bc6a4e0.png +0 -0
  92. kaa/sprites/9f573ac2-9d28-4d92-8e3f-1b78031220dd.png +0 -0
  93. kaa/sprites/__pycache__/__init__.cpython-310.pyc +0 -0
  94. kaa/sprites/a2545c5c-b5cc-4fd2-93c1-04c74c17ee16.png +0 -0
  95. kaa/sprites/a2dd125b-9868-4e01-9a46-3b552c2ebdc9.png +0 -0
  96. kaa/sprites/a7f25aeb-d91b-47e0-ba1a-0c6382380102.png +0 -0
  97. kaa/sprites/a888e87e-49fe-405d-b074-3dda30304808.png +0 -0
  98. kaa/sprites/a9ba2741-38da-4448-ab80-f0e5b3c3847f.png +0 -0
  99. kaa/sprites/a9c5aeb0-c0c9-47da-8793-ffe8d172bea0.png +0 -0
  100. kaa/sprites/aba47934-f264-49f9-a72c-6ed90b112701.png +0 -0
  101. kaa/sprites/abe2757f-84f3-4967-bd05-79c17cb1f32c.png +0 -0
  102. kaa/sprites/acd741da-d4ab-4b76-a6a3-4a2fd25870ef.png +0 -0
  103. kaa/sprites/ad17ae00-f6ce-4f32-9386-9a8073b5e79a.png +0 -0
  104. kaa/sprites/ae73d26b-2d47-4921-a6ec-5bbea32773a3.png +0 -0
  105. kaa/sprites/b10281ae-cfaf-4400-b2fb-c8c2b432c8e7.png +0 -0
  106. kaa/sprites/b40bebbf-2800-40fb-b7a2-1c2d5995e747.png +0 -0
  107. kaa/sprites/b76add75-2187-428c-9ede-fb43086bacb6.png +0 -0
  108. kaa/sprites/b77a7e97-dc59-493d-9d76-4ea9c2876978.png +0 -0
  109. kaa/sprites/b9770cd2-b55f-44dc-965f-f29686fba7da.png +0 -0
  110. kaa/sprites/ba8ee2cd-f662-440c-90b3-1e4bfe7bab6b.png +0 -0
  111. kaa/sprites/bb3990c8-4618-4d96-9365-a4d1213b59f7.png +0 -0
  112. kaa/sprites/bbe59f62-c3e7-404c-a313-b50db70de7b5.png +0 -0
  113. kaa/sprites/bdb1460e-c5db-494a-a58a-688f72b6bdba.png +0 -0
  114. kaa/sprites/bdb72f31-5808-4451-827f-fffc3b616083.png +0 -0
  115. kaa/sprites/bf3ff37e-d4fc-42ee-87d6-db1e2040aed5.png +0 -0
  116. kaa/sprites/bff753bb-b02e-441b-89e5-14845f18c6f6.png +0 -0
  117. kaa/sprites/c035ac76-39e9-466b-a606-28bc52bc73e8.png +0 -0
  118. kaa/sprites/c05a600a-d79e-432d-a49f-5b2443d67bd4.png +0 -0
  119. kaa/sprites/c0801be3-f07a-4afc-ab0d-7f5d3c4afbd3.png +0 -0
  120. kaa/sprites/c2100faf-1234-49db-b6d4-5a08a4b08272.png +0 -0
  121. kaa/sprites/c6b0f9ba-a976-474b-b22d-6fe4391d9373.png +0 -0
  122. kaa/sprites/c78fb143-18e3-4697-a0c1-6151514f2a7c.png +0 -0
  123. kaa/sprites/c8c17304-e949-4dfc-b07d-9e7133483e31.png +0 -0
  124. kaa/sprites/c91874f4-363f-4997-a38e-3e486dfd8043.png +0 -0
  125. kaa/sprites/c9245201-4d29-4088-a5e0-f4e93d4494b5.png +0 -0
  126. kaa/sprites/cb0bbf0f-a25b-4ec4-99bd-f5742270a062.png +0 -0
  127. kaa/sprites/ccfab3e2-7b6d-4ae3-998b-4e5c1863884a.png +0 -0
  128. kaa/sprites/cdf310f0-b917-4f92-95a9-893af76e3c3a.png +0 -0
  129. kaa/sprites/cea8f98d-ba68-498f-bd3d-cc10f0d4575b.png +0 -0
  130. kaa/sprites/cec36685-85a7-4e84-bbbc-4df70b4f7bac.png +0 -0
  131. kaa/sprites/cf49878d-a1c5-4b9f-9502-1e0d9eaadc49.png +0 -0
  132. kaa/sprites/d23a600a-7002-4268-96a4-18dc54928ec6.png +0 -0
  133. kaa/sprites/d57f792a-f086-4fbe-b4d9-5db629a78d42.png +0 -0
  134. kaa/sprites/d6dd92b3-310f-4f5d-a8ef-b941c3659c0c.png +0 -0
  135. kaa/sprites/d8967770-c64a-4609-a0a5-f46ba81edceb.png +0 -0
  136. kaa/sprites/d91483a2-83fa-4664-8eda-52498c0e77bc.png +0 -0
  137. kaa/sprites/d9a636be-a017-4ef5-a70c-c374827008a0.png +0 -0
  138. kaa/sprites/dae37bd7-6a34-4eb4-8cd0-3c0c03b4575a.png +0 -0
  139. kaa/sprites/dc51eccf-9470-495a-9e38-59d4481adbd4.png +0 -0
  140. kaa/sprites/dcea5aae-322e-4cd4-b218-0eac48690755.png +0 -0
  141. kaa/sprites/dcf465c6-ad64-48e7-9c3c-7bc7cfc13a44.png +0 -0
  142. kaa/sprites/ddb59f04-91a0-4fbd-8921-be13acdab291.png +0 -0
  143. kaa/sprites/de81f919-4d01-4a4e-bdc1-ffe6e23a5c22.png +0 -0
  144. kaa/sprites/e05f2c16-926f-48be-bdd0-16182e879394.png +0 -0
  145. kaa/sprites/e2a0c1a6-c0cf-400e-99be-1ed0d35c6ed8.png +0 -0
  146. kaa/sprites/e30922ed-a02f-4ede-9968-1656be5a05b2.png +0 -0
  147. kaa/sprites/e388db01-0870-412d-b8bc-5a512ec997c8.png +0 -0
  148. kaa/sprites/e392856d-ac59-4414-8fb8-df93a1a99be4.png +0 -0
  149. kaa/sprites/e57db8c2-c050-43fb-8205-339aeb5875e8.png +0 -0
  150. kaa/sprites/e687c2ba-2c30-4fc8-804f-fea5815f6765.png +0 -0
  151. kaa/sprites/e6e66204-8a2f-4377-8674-b7d663ff0081.png +0 -0
  152. kaa/sprites/e79a2a08-3b58-4ab0-8c2b-769f30cc8591.png +0 -0
  153. kaa/sprites/ebe22aea-0318-49d8-ab07-ce2eef34265f.png +0 -0
  154. kaa/sprites/ed6df33a-c7aa-4542-a87b-9cc9cae0465c.png +0 -0
  155. kaa/sprites/ed854df1-878c-4e0b-8138-9b28d314ede6.png +0 -0
  156. kaa/sprites/ed98a341-5dff-4af7-a194-d28232d481a4.png +0 -0
  157. kaa/sprites/f0ed1dd3-b227-48c1-8c8c-858dbd84fcc7.png +0 -0
  158. kaa/sprites/f1eb4089-8cd1-4830-b00e-40535ddcd116.png +0 -0
  159. kaa/sprites/f237d88e-92ac-4ebf-85e1-80a696b5203a.png +0 -0
  160. kaa/sprites/f2f818c9-b0cf-436d-9d3e-6544c5399063.png +0 -0
  161. kaa/sprites/f333118a-81c2-417f-b54f-64dc4e8df613.png +0 -0
  162. kaa/sprites/f34e8026-bdfc-47e6-a0ed-49e587ef0f40.png +0 -0
  163. kaa/sprites/f3a5992b-dabf-4c2b-83e9-4c91c3b7aac8.png +0 -0
  164. kaa/sprites/f4195ceb-586a-4a8c-9424-4962239d2120.png +0 -0
  165. kaa/sprites/f485db66-2159-4d31-ba53-0fbb726e7f64.png +0 -0
  166. kaa/sprites/f7264cee-fea6-47b5-9f9b-8f3f31c03ea0.png +0 -0
  167. kaa/sprites/f7e34403-a53c-4d3f-935b-25b4acb7f7a5.png +0 -0
  168. kaa/sprites/f8d8c943-1b36-4391-a7fc-2a49f8966d53.png +0 -0
  169. kaa/sprites/f9157db8-d70b-4d46-9800-5a833ce7eda8.png +0 -0
  170. kaa/sprites/f9a353b2-958d-4aae-ade4-66bdc6481e35.png +0 -0
  171. kaa/sprites/fa5b5b92-9c60-4811-a44c-8e897c9632c3.png +0 -0
  172. kaa/sprites/fac7b90a-1174-477b-803b-28798647c307.png +0 -0
  173. kaa/sprites/fbbb73f9-880e-4c7f-9ec9-276bdab4b394.png +0 -0
  174. kaa/sprites/fce4a481-e71c-4dab-aeac-59ff8b18201b.png +0 -0
  175. kaa/sprites/fd8a7a5d-f021-4bfd-83f7-a2dd33325837.png +0 -0
  176. kaa/sprites/fda4b3eb-e31a-448b-8cb3-9126e1ab7deb.png +0 -0
  177. kaa/sprites/fda78372-04b4-4d55-92b1-aedec20d0913.png +0 -0
  178. kaa/sprites/fe993a91-1a49-488e-b7ff-c1b05b8f2b5f.png +0 -0
  179. kaa/sprites/ff8efb8f-e1a4-4202-a6e1-680eb44f58da.png +0 -0
  180. kaa/tasks/R.py +128 -128
  181. kaa/tasks/common.py +5 -0
  182. kaa/tasks/daily/contest.py +2 -1
  183. kaa/tasks/produce/cards.py +5 -4
  184. kaa/tasks/produce/common.py +201 -105
  185. kaa/tasks/produce/in_purodyuusu.py +14 -10
  186. kaa/tasks/produce/non_lesson_actions.py +10 -33
  187. kaa/tasks/produce/p_drink.py +5 -1
  188. kaa/tasks/produce/produce.py +2 -1
  189. kaa/tasks/start_game.py +2 -1
  190. {ksaa-2025.11b1.dist-info → ksaa-2025.11b3.dist-info}/METADATA +9 -6
  191. {ksaa-2025.11b1.dist-info → ksaa-2025.11b3.dist-info}/RECORD +323 -177
  192. /kaa/sprites/{fdf0da06-f088-424f-9941-8c883fea3db3.png → 03d0acec-15fd-4c21-82ce-122764def185.png} +0 -0
  193. /kaa/sprites/{68d9f340-a3d2-4708-8eb1-c1ed857decda.png → 03d22cb3-0193-4dcb-8a0d-98b7ca9c2b4c.png} +0 -0
  194. /kaa/sprites/{dce410ee-fa56-41c4-b75e-e1bff79cd94f.png → 0455e229-75c9-44ba-8729-745799746979.png} +0 -0
  195. /kaa/sprites/{ad94041c-f30b-40b9-b11a-1a26e9962274.png → 049ecbf6-d434-46fa-a42c-a447475269bb.png} +0 -0
  196. /kaa/sprites/{f6b042a8-a91e-4811-99f9-18bbb5197468.png → 04ea8503-cdd5-4b3e-a33b-63893b92f6ba.png} +0 -0
  197. /kaa/sprites/{847226a3-b7d2-4156-b732-9215a3e14f3a.png → 05251a85-2883-4098-842e-6544391de919.png} +0 -0
  198. /kaa/sprites/{9008fbb2-f23f-424f-9be7-5bae6a3697ab.png → 054db45e-1434-4604-91ec-7ac586ca11b5.png} +0 -0
  199. /kaa/sprites/{ae1e70bc-f735-4749-8c23-95735b91897a.png → 06cf74aa-635f-48ab-b965-36981f2063d3.png} +0 -0
  200. /kaa/sprites/{3b4f90c9-6de7-4ac3-8e41-5f8757bf3f3e.png → 0814c0fd-6f89-47d3-8089-e8cfde569750.png} +0 -0
  201. /kaa/sprites/{2cec1d6a-9e8c-49b3-b885-0b0d7c4b95ee.png → 08bde3ff-7554-4bdb-a7f0-193323489d5b.png} +0 -0
  202. /kaa/sprites/{91b30f5e-31b2-4756-a3f7-f0f82a335442.png → 09222fb0-78a6-4663-8c1f-1d44e881513d.png} +0 -0
  203. /kaa/sprites/{5431dc38-c257-40b3-8f7b-8bceaa7fe587.png → 0b436edb-8f6a-429d-87b7-5d4250f651ac.png} +0 -0
  204. /kaa/sprites/{338d7e71-98ce-4cd1-9954-bf7155150780.png → 0c266b0e-de7a-49c1-9709-b01fb5086f75.png} +0 -0
  205. /kaa/sprites/{8e019262-ad23-4cbb-84da-86b34775a91e.png → 0db579bf-d555-4468-8104-c2d2e68d33b1.png} +0 -0
  206. /kaa/sprites/{8be81341-a74d-42c8-8231-5d1854bc08e7.png → 114730f6-eddd-4381-b723-aee18cde0d90.png} +0 -0
  207. /kaa/sprites/{31f2de0a-567b-425a-9be6-536e4532d813.png → 11870372-dc78-4a80-8320-15bb24da6f25.png} +0 -0
  208. /kaa/sprites/{3fa5f81c-9223-44ba-bf07-71932350e845.png → 11bc7d35-e58d-4301-a0b0-f557dbd73c7b.png} +0 -0
  209. /kaa/sprites/{92c3de1b-eed1-45b9-82e0-c9e97bb479e7.png → 12455dbd-7d70-4435-a3ba-f40654e75c37.png} +0 -0
  210. /kaa/sprites/{aa1624ff-88b0-447b-8e2b-8a50fd9e4062.png → 12f330a6-4eab-4015-b0e3-4e1a35a7b676.png} +0 -0
  211. /kaa/sprites/{9991b19c-7330-42c4-9d7d-db3cb00103b7.png → 14a697d4-0b58-4644-bb2d-8823d2fefcb8.png} +0 -0
  212. /kaa/sprites/{49bde219-f9a3-41b5-84b8-e417160a0f40.png → 15605f7a-2206-436c-8a71-011d9f95cf4e.png} +0 -0
  213. /kaa/sprites/{ea430652-e263-4a15-bb6f-8a8807be6c8f.png → 15dd89cc-53ed-4c77-a355-62e3bd7a15dd.png} +0 -0
  214. /kaa/sprites/{5c310fe5-7e92-4167-9eba-6e8e14a2863a.png → 18b13508-c46f-4134-b991-975c0a1b9a74.png} +0 -0
  215. /kaa/sprites/{cd00a2d7-af48-48b1-b2e1-5360ceed249f.png → 1a5c147b-e28e-42ad-893a-7430d8f4fc35.png} +0 -0
  216. /kaa/sprites/{94d54ba7-0ccf-4fd9-a5bf-488bac1364c8.png → 1b3c84c5-16d1-43a7-8513-719bd7a10450.png} +0 -0
  217. /kaa/sprites/{2289d38f-dc98-4310-9f34-4cf5023f8545.png → 1b847790-90e2-44f8-b6d9-4814812006bd.png} +0 -0
  218. /kaa/sprites/{6c926e92-9af9-402d-8512-6417ca116928.png → 1e57ab88-9962-4024-81df-746529a758f9.png} +0 -0
  219. /kaa/sprites/{30e12bf1-8fa5-4de1-8d7b-28fa0fec0cb6.png → 205e03de-46d9-4983-a2ea-a7f7500d508f.png} +0 -0
  220. /kaa/sprites/{e4dc3b35-195c-415f-9484-c2459bd8675a.png → 20bd834e-c99c-4e80-92db-0740e5bbe746.png} +0 -0
  221. /kaa/sprites/{68e20ebf-02fd-46a1-88d7-b4472824e7bc.png → 218a6ab3-93f6-4bb1-9848-8c97ff695945.png} +0 -0
  222. /kaa/sprites/{ec3cad5f-e0c9-4577-8499-79b50248344e.png → 22071c63-a1bc-4163-8d5a-973b3d579c76.png} +0 -0
  223. /kaa/sprites/{e933cd55-e47a-4327-89d7-b25995cb4a3f.png → 2460d0c9-50e2-451b-b609-ad466b574395.png} +0 -0
  224. /kaa/sprites/{0af1d573-1dc7-427e-997d-173308ea3649.png → 264d021a-b322-4472-8a7b-5f1322aba993.png} +0 -0
  225. /kaa/sprites/{57c81080-7b53-4286-8fa5-848ad63e4774.png → 28335ba3-9a0f-46cd-b66d-047781773264.png} +0 -0
  226. /kaa/sprites/{d7750f81-de10-4d6f-9cc7-35223bda9d70.png → 28df544b-72f2-4ed8-8bf3-609ff99633d9.png} +0 -0
  227. /kaa/sprites/{81686816-c723-47d1-9824-a68d9ebe1bd4.png → 2a82e2d6-0722-433a-87fa-f1752ce0b9b7.png} +0 -0
  228. /kaa/sprites/{5ffd3f29-db4f-4f66-b9ed-be5a70b7ebf9.png → 2abce6a4-111f-42bb-9255-f98d544108de.png} +0 -0
  229. /kaa/sprites/{23b9cda9-8be8-438e-8e54-57d91a4bd875.png → 2d8e6464-aceb-41fd-9e78-7523738d5720.png} +0 -0
  230. /kaa/sprites/{1ad89ee4-1bb1-41d2-a92c-79caf6baa38a.png → 2f9e2dbb-66a1-4b13-9b9e-d62e10efa6d3.png} +0 -0
  231. /kaa/sprites/{c69dcdcf-42a7-420e-aa8e-bb8639ea80b6.png → 307b58f0-20c1-41bd-9eaa-1337fd0e6563.png} +0 -0
  232. /kaa/sprites/{55c3af20-58dc-4407-a383-312a57417c39.png → 3192a62f-224d-44b1-a0b9-b1fc22de8ec1.png} +0 -0
  233. /kaa/sprites/{645909d7-b960-46c7-b208-db44b6b7feec.png → 31b4c370-696f-4dfc-a918-839495520266.png} +0 -0
  234. /kaa/sprites/{7daaca55-e3fd-4e12-bf31-872105ceb726.png → 330c2207-af32-453b-8db7-889cda83e7cc.png} +0 -0
  235. /kaa/sprites/{5734e48a-1e58-42de-be7b-b7db67db4a01.png → 38186efc-850c-4d83-97bc-9417f1494b94.png} +0 -0
  236. /kaa/sprites/{8ed51be4-815c-4a3d-805e-030fdfa341e2.png → 38426696-ff13-4f20-9f74-b05855990153.png} +0 -0
  237. /kaa/sprites/{cfe3563d-a24b-4197-a0cb-5628bd990c08.png → 3a211792-1243-496a-b41e-0e3fd121cd5b.png} +0 -0
  238. /kaa/sprites/{179c0fff-ebd2-4a16-8db2-297552cca218.png → 3a4e2d8a-deca-4980-b6c2-37bfc17d2720.png} +0 -0
  239. /kaa/sprites/{2d0e9d49-365a-4bcb-a416-38b87defaa3c.png → 3a4ec054-2c48-4359-afb9-fa5ea8191d16.png} +0 -0
  240. /kaa/sprites/{51b95c81-4ff9-434c-ade2-3518e63337cb.png → 3c490171-6810-44f0-b28d-c6b664347a3c.png} +0 -0
  241. /kaa/sprites/{35341839-4469-4ab6-aa40-33642fe43e82.png → 3cda578a-fa75-4bbd-9cff-be4bc4355a58.png} +0 -0
  242. /kaa/sprites/{72634cb3-4c76-4ca2-8898-ebb837ec19e3.png → 3ea03db7-4de9-45c4-a07b-a9bbc2c63e70.png} +0 -0
  243. /kaa/sprites/{da48db0d-09d9-47c3-9e08-8b69ad547be6.png → 3ea8e354-2684-46f3-9f5a-43f094717c95.png} +0 -0
  244. /kaa/sprites/{3e087b8d-420d-48ff-b526-29c4a65d8cbe.png → 3eb9b21b-abbe-49fd-a3a9-6e1c1a6e91d9.png} +0 -0
  245. /kaa/sprites/{2234f709-1703-4589-905c-175f4db09b1b.png → 3fb84a71-ed15-4989-9598-34e7342f38f5.png} +0 -0
  246. /kaa/sprites/{39f6d657-3b3e-40aa-849b-7ad87a0be1d0.png → 3ffd2992-fa55-499c-8c3b-193518ebbe07.png} +0 -0
  247. /kaa/sprites/{464b1dd8-ca2e-41e9-a5b5-90545c584db7.png → 41ff9641-d200-4caa-bcfa-d8389a3438eb.png} +0 -0
  248. /kaa/sprites/{70768479-5d7a-4941-8774-ad556c47bee2.png → 455dcf19-63f5-4b0a-99e6-b23d3876d199.png} +0 -0
  249. /kaa/sprites/{694879e8-ecca-45e2-8ea4-1b447fd43ace.png → 45f09e08-53ea-4e08-97dc-70f689bab002.png} +0 -0
  250. /kaa/sprites/{dd873ac0-ffba-4335-9cf2-2162c6835ed8.png → 4729b509-0f4a-4e96-b186-ec56c680c9e6.png} +0 -0
  251. /kaa/sprites/{7d7df15f-707e-4e27-826f-21e42af1dae0.png → 4eb665ef-7741-40f9-8174-7b6ca66d045b.png} +0 -0
  252. /kaa/sprites/{8e5e968b-edad-4c03-abc8-3f2a7e8879ae.png → 4f370ff6-61d1-405a-b29e-e6d0b3072194.png} +0 -0
  253. /kaa/sprites/{f0462447-5226-4819-a39b-19ab90583f83.png → 504e4927-bfeb-43ee-aa5c-35cec664a4c8.png} +0 -0
  254. /kaa/sprites/{756f4ca7-acac-48e1-8bcd-1c5cd8937e3a.png → 51eb4be2-22fa-4683-82c7-513f5934f7b9.png} +0 -0
  255. /kaa/sprites/{87f3c1ae-5117-4871-a7d6-3f5ff0c9f9fb.png → 568608bd-a1fa-4faf-ae15-179563a7e84f.png} +0 -0
  256. /kaa/sprites/{978873bb-e4d0-451b-9126-6977144f5395.png → 56ac84af-4c85-4b69-b449-98981c1df292.png} +0 -0
  257. /kaa/sprites/{db6707a2-2964-4919-9992-4d801fa43dae.png → 5a49b6d2-2bcb-49bc-a28f-b8bd1441f60a.png} +0 -0
  258. /kaa/sprites/{01256311-237c-476f-96ce-4136dc4bfbd3.png → 5a677634-99cf-45b5-bc0c-94120872a518.png} +0 -0
  259. /kaa/sprites/{8e4d8a0f-4a9d-4562-9234-63806b11d85f.png → 5ec51718-1403-4a79-bd85-46e1fe04d8c9.png} +0 -0
  260. /kaa/sprites/{dc97fea3-898f-4135-9c40-ad41570ab4ae.png → 5f2d0b2b-8425-4dd8-8b85-d62f4b75286c.png} +0 -0
  261. /kaa/sprites/{f32a41a2-c482-41ba-b718-28f048f5148c.png → 5f4abae0-a1f0-4c8c-9d93-a8525caa9dd0.png} +0 -0
  262. /kaa/sprites/{31e3ac2b-ecd4-4c37-88bc-985ef32e73a3.png → 6005bf30-fd7c-401e-8efd-050fa97ad7f3.png} +0 -0
  263. /kaa/sprites/{3b4dc708-1d34-4a88-9fe3-d8de2ec1d5c8.png → 6069f8bc-2a06-45a4-95ca-1ac9d8fa3b04.png} +0 -0
  264. /kaa/sprites/{962aa0b9-1dd3-4260-a4fb-c069c26e5a84.png → 60896822-de58-4e07-b2d9-86a7f4068de1.png} +0 -0
  265. /kaa/sprites/{889a4153-b713-49cb-a4d5-e302bcdd002d.png → 622d700e-0fd8-4a92-a286-1e8143c70570.png} +0 -0
  266. /kaa/sprites/{b59c0e9b-1f20-4194-ab37-286f505fa656.png → 63b74752-73ce-4020-a7c8-0a71a9f67415.png} +0 -0
  267. /kaa/sprites/{4a081370-b0a1-4067-8470-e3007cc68a12.png → 648d43f6-b251-4d6f-a808-ae7325c91a59.png} +0 -0
  268. /kaa/sprites/{bfdc9b53-2fe5-43f1-8588-7ab71217d31c.png → 65f79941-1c78-496a-a67c-c50f4227bd34.png} +0 -0
  269. /kaa/sprites/{9e7eaa8e-3178-44da-a5ec-34b889f8facf.png → 6f50cd3b-6e46-46c5-99ed-26728d3212ad.png} +0 -0
  270. /kaa/sprites/{ab237c6d-c4d8-4716-8ef7-99b8e995c9a7.png → 6f6d7af3-8380-439b-9d26-3fbd5a103b49.png} +0 -0
  271. /kaa/sprites/{1befe09b-cb77-417a-b21e-7746804d4e03.png → 71913fde-c3db-463d-800d-e1b35fa2c8b4.png} +0 -0
  272. /kaa/sprites/{e7f2734f-9fdc-4521-8d7e-8b0fe270a223.png → 71976c1a-5df9-44a5-b4ea-08b5d617d813.png} +0 -0
  273. /kaa/sprites/{9f7150bc-c0b8-48d6-862c-456aaf518b2b.png → 72a8bcd2-3f32-4ee5-8295-eedf441d6a1a.png} +0 -0
  274. /kaa/sprites/{cd0e8663-2ea1-436a-b9fb-3caa0c3ed9e8.png → 73b6f3aa-5179-41d6-a82e-22e14aa8cd6a.png} +0 -0
  275. /kaa/sprites/{cba0646d-dffe-4c5b-a44d-1f8d827624a6.png → 7a74b5f5-7a04-4678-8e6e-57b5de127182.png} +0 -0
  276. /kaa/sprites/{5930140e-effe-4bcf-b0be-c20d3990d833.png → 7b4c3a81-8f09-4a00-90ee-d4df3f57e863.png} +0 -0
  277. /kaa/sprites/{cb6dffd9-6474-4d09-aee6-26352ea51d31.png → 7c4ca388-5167-478a-a32b-0e108edad888.png} +0 -0
  278. /kaa/sprites/{96704aa3-b5ad-4e34-bb88-fad766415362.png → 7d4709f8-6d0d-493f-819e-74cb0f7c166b.png} +0 -0
  279. /kaa/sprites/{fcc72120-2a77-4c26-a27e-e1027c6088c0.png → 7e8904fd-5863-471f-8e9a-d69d9ca72f8f.png} +0 -0
  280. /kaa/sprites/{023b8f4c-15ab-4845-b141-446c861ad475.png → 80800c2e-417d-4118-b726-93aaabfc08bd.png} +0 -0
  281. /kaa/sprites/{f0aef696-2106-46a4-8b7f-9f16b6c89d3f.png → 81b1b160-2d0f-42ad-924a-9572a54f343a.png} +0 -0
  282. /kaa/sprites/{13cb0309-b713-4725-b10b-26afe46eb9c0.png → 82259f79-2bef-442b-bf16-78cb4f22e3be.png} +0 -0
  283. /kaa/sprites/{43a367e1-91dd-495e-8c30-41903f75a99a.png → 861a4faa-2522-41e9-8e20-7bd9180bea5a.png} +0 -0
  284. /kaa/sprites/{01247ebe-8d63-4573-90f4-d8dc2b7ca14c.png → 87ed135a-2eb1-4e21-8928-d0307a22ea66.png} +0 -0
  285. /kaa/sprites/{1cf03f98-63e9-467c-804d-c74dd97b69bd.png → 8805fead-f7e2-4905-a42e-05ebba2fbe21.png} +0 -0
  286. /kaa/sprites/{16a0fd47-e85b-4848-8894-9d071ea993ac.png → 88be2dcc-68ca-4596-9b2c-544a196cab64.png} +0 -0
  287. /kaa/sprites/{a5694c76-3c5d-462e-81d5-1e0e6cef0ec9.png → 89841ff0-e834-4a7e-b9d5-00a9490b6b7f.png} +0 -0
  288. /kaa/sprites/{84cabff2-7a1b-4018-b74b-46f4db06304f.png → 8bf08bab-7c55-45e1-8433-c2213a323480.png} +0 -0
  289. /kaa/sprites/{e5e49b44-dcc2-4e77-9180-0d2beaa3f9ad.png → 8d416e23-04ef-47bd-8cc8-7f18d1bab736.png} +0 -0
  290. /kaa/sprites/{c1d502eb-c77f-45cb-86b5-11b4a8a3aef5.png → 8f9dd0f0-f9af-4eec-a89e-8f2c92f88a98.png} +0 -0
  291. /kaa/sprites/{424a0ef5-102d-4734-a731-2b3b3c7c9682.png → 9088f8c0-59f8-41c6-994c-ae283ac94c24.png} +0 -0
  292. /kaa/sprites/{91a50322-52d9-4516-9e46-bc121f20667d.png → 922af7d1-75e9-4ac8-a4e7-2dad8bb1ca87.png} +0 -0
  293. /kaa/sprites/{d81b1325-e57a-4f22-93e1-6ad4baa28935.png → 94ed55fe-3ef8-46bc-855a-a7b1dedab801.png} +0 -0
  294. /kaa/sprites/{913dbd4e-ebb1-4c9f-b145-9960cde59c17.png → 95d715c3-d569-48b5-be7b-c21cd2a160db.png} +0 -0
  295. /kaa/sprites/{dd7bd6cd-90f1-4773-9b68-5df7f2f84da5.png → 97a3791d-fa9d-453d-8081-c574fe88b823.png} +0 -0
  296. /kaa/sprites/{2204967a-a0ee-4dd3-aecb-4d531e8e954c.png → 9acd9a59-004f-4e1d-a208-0c293f2702d5.png} +0 -0
  297. /kaa/sprites/{572a921d-633f-4465-b177-7a0d9ad7e099.png → 9f3bfe36-8462-404f-94da-9bc324b1beed.png} +0 -0
  298. /kaa/sprites/{799fe395-2264-4bc5-b515-813dadda8fe1.png → 9f46f543-d7dc-4836-a210-125d686475f9.png} +0 -0
  299. /kaa/sprites/{5bf2a814-df85-4d0a-b4b5-8883ac2ee434.png → a34502b4-10bd-42ca-9ada-a9cdb57097dc.png} +0 -0
  300. /kaa/sprites/{043e753e-db15-45ba-8513-53c3fc9c7f3c.png → a3fe5859-62ba-403e-9367-65db0ad15943.png} +0 -0
  301. /kaa/sprites/{8f7b55d8-0143-4d27-bef8-560d4d510500.png → a42ac612-acbd-45cc-88fb-104ff9b7d2d8.png} +0 -0
  302. /kaa/sprites/{736a9daf-05d6-46ba-810b-5a8f509152d1.png → a4c6d967-0251-4b33-acb3-81d24f82d5a4.png} +0 -0
  303. /kaa/sprites/{edcec31d-d5de-4f22-b666-3e3c656e06d8.png → a6ed21f0-4da4-4065-bb59-062a70e132ca.png} +0 -0
  304. /kaa/sprites/{e9310e38-a418-4561-bf33-eb3e6dccf477.png → a97e2840-1575-4f2c-97df-6a720c644969.png} +0 -0
  305. /kaa/sprites/{d644faa3-ff16-417f-928c-4c62b040bfdb.png → ae0ce964-eb8f-45a1-aa4d-f47a5c8c720f.png} +0 -0
  306. /kaa/sprites/{256ffeba-8e9e-4cc5-8a1c-9eaee427f1a5.png → ae106b38-da4f-4b0d-b9c3-541fd58f4de7.png} +0 -0
  307. /kaa/sprites/{802db04f-77c2-46a4-a6eb-f81d48ea03ce.png → aeab8f9a-fe61-4c2d-a494-ffc19a9cae91.png} +0 -0
  308. /kaa/sprites/{37215a56-f8e1-4f22-a148-9894136f6ab1.png → affc87db-2f63-4e4a-855e-6ff608226f1e.png} +0 -0
  309. /kaa/sprites/{d1ea0ea6-4a6a-4036-b140-922c95a648b5.png → b02c15b5-04b4-40d9-bb13-267786e8e049.png} +0 -0
  310. /kaa/sprites/{22dc4cfe-8c66-4461-8660-e2d11bbe6154.png → b7f62cab-cc24-480e-bf4c-25c43a1e801e.png} +0 -0
  311. /kaa/sprites/{5906d986-d0e5-452d-a7c4-ddeb7af8751d.png → bd4cd421-f702-47c0-9f8b-77914973108c.png} +0 -0
  312. /kaa/sprites/{8bd22fe1-b544-4d2e-b74a-34f3cf0eb512.png → c4505a31-74c5-4b3d-bfcf-a67c3ef0039e.png} +0 -0
  313. /kaa/sprites/{e13fc34b-accc-4986-865d-f8d8410b45e9.png → c6b6b77b-2ec7-4fb7-8033-f4d061f4e9c8.png} +0 -0
  314. /kaa/sprites/{2b6d2eb0-bcf7-4bea-b037-6293d9c6d728.png → c76c6ccb-d099-4c3c-9eda-13be33aa48ae.png} +0 -0
  315. /kaa/sprites/{0562f69f-0300-4a2b-8252-63f3e7180e4c.png → cb15d9a3-78fe-4f03-bd23-90ba6169ddff.png} +0 -0
  316. /kaa/sprites/{2a8626df-056c-46a2-aaf3-0060a5aef6a3.png → d1bdfa3b-34df-488d-9f9b-8c7b04dd4ab3.png} +0 -0
  317. /kaa/sprites/{3aed50a2-d640-4178-9b8a-4dd7973eebf1.png → d8ba1932-978c-451c-a717-d7d2b6db35d9.png} +0 -0
  318. /kaa/sprites/{f635499a-943d-47da-952a-1feb58daa25b.png → e7630ccb-6824-49e3-986f-2a65a2c4a948.png} +0 -0
  319. /kaa/sprites/{847eb5c0-0350-4b7c-9c9c-43c796709795.png → ec35a0b8-1afa-48ff-ae66-9c1ef966348d.png} +0 -0
  320. {ksaa-2025.11b1.dist-info → ksaa-2025.11b3.dist-info}/WHEEL +0 -0
  321. {ksaa-2025.11b1.dist-info → ksaa-2025.11b3.dist-info}/entry_points.txt +0 -0
  322. {ksaa-2025.11b1.dist-info → ksaa-2025.11b3.dist-info}/licenses/LICENSE +0 -0
  323. {ksaa-2025.11b1.dist-info → ksaa-2025.11b3.dist-info}/top_level.txt +0 -0
kaa/main/gr.py CHANGED
@@ -34,6 +34,11 @@ from kaa.config import (
34
34
  from kaa.config.produce import ProduceSolution, ProduceSolutionManager, ProduceData
35
35
  from kaa.application.adapter.misc_adapter import create_desktop_shortcut
36
36
  from kaa.application.core.idle_mode import IdleModeManager
37
+ from kaa.application.core.update_service import UpdateService
38
+ from kaa.application.core.feedback_service import FeedbackService
39
+ from kaa.errors import (
40
+ ProduceSolutionNotFoundError, UpdateServiceError, UpdateFetchListError, FeedbackServiceError
41
+ )
37
42
 
38
43
  logger = logging.getLogger(__name__)
39
44
  GradioInput = gr.Textbox | gr.Number | gr.Checkbox | gr.Dropdown | gr.Radio | gr.Slider | gr.Tabs | gr.Tab
@@ -59,7 +64,7 @@ ConfigKey = Literal[
59
64
  'select_which_contestant', 'when_no_set',
60
65
 
61
66
  # produce
62
- 'produce_enabled', 'selected_solution_id', 'produce_count', 'produce_timeout_cd', 'enable_fever_month',
67
+ 'produce_enabled', 'selected_solution_id', 'produce_count', 'produce_timeout_cd', 'interrupt_timeout', 'enable_fever_month',
63
68
  'mission_reward_enabled',
64
69
 
65
70
  # club reward
@@ -92,7 +97,7 @@ ConfigKey = Literal[
92
97
  'trace_recommend_card_detection',
93
98
 
94
99
  # misc
95
- 'check_update', 'auto_install_update', 'expose_to_lan', 'update_channel',
100
+ 'check_update', 'auto_install_update', 'expose_to_lan', 'update_channel', 'log_level',
96
101
 
97
102
  # idle
98
103
  'idle_enabled', 'idle_seconds', 'idle_minimize_on_pause',
@@ -104,128 +109,6 @@ CONFIG_KEY_VALUE: tuple[str] = get_args(ConfigKey)
104
109
  ConfigSetFunction = Callable[[BaseConfig, Dict[ConfigKey, Any]], None]
105
110
  ConfigBuilderReturnValue = Tuple[ConfigSetFunction, Dict[ConfigKey, GradioInput]]
106
111
 
107
- def _save_bug_report(
108
- title: str,
109
- description: str,
110
- version: str,
111
- upload: bool,
112
- path: str | None = None
113
- ) -> Generator[str, None, str]:
114
- """
115
- 保存报告
116
-
117
- :param title: 标题
118
- :param description: 描述
119
- :param version: 版本号
120
- :param upload: 是否上传
121
- :param path: 保存的路径。若为 `None`,则保存到 `./reports/bug-YY-MM-DD HH-MM-SS_标题.zip`。
122
- :return: 保存的路径
123
- """
124
- from kotonebot import device
125
- from kotonebot.backend.context import ContextStackVars
126
- import re
127
-
128
- # 过滤标题中的非法文件名字符
129
- def sanitize_filename(s: str) -> str:
130
- # 替换 \/:*?"<>| 为空或下划线
131
- return re.sub(r'[\\/:*?"<>|]', '_', s)
132
-
133
- # 确保目录存在
134
- os.makedirs('logs', exist_ok=True)
135
- os.makedirs('reports', exist_ok=True)
136
-
137
- error = ""
138
- if path is None:
139
- safe_title = sanitize_filename(title)[:30] or "无标题"
140
- timestamp = datetime.now().strftime("%y-%m-%d-%H-%M-%S")
141
- path = f'./reports/bug_{timestamp}_{safe_title}.zip'
142
- with zipfile.ZipFile(path, 'w', zipfile.ZIP_DEFLATED, compresslevel=9) as zipf:
143
- # 打包描述文件
144
- yield "### 打包描述文件..."
145
- try:
146
- description_content = f"标题:{title}\n类型:bug\n内容:\n{description}"
147
- zipf.writestr('description.txt', description_content.encode('utf-8'))
148
- except Exception as e:
149
- error += f"保存描述文件失败:{str(e)}\n"
150
-
151
- # 打包截图
152
- yield "### 打包上次截图..."
153
- try:
154
- stack = ContextStackVars.current()
155
- screenshot = None
156
- if stack is not None:
157
- screenshot = stack._screenshot
158
- if screenshot is not None:
159
- img = cv2.imencode('.png', screenshot)[1].tobytes()
160
- zipf.writestr('last_screenshot.png', img)
161
- if screenshot is None:
162
- error += "无上次截图数据\n"
163
- except Exception as e:
164
- error += f"保存上次截图失败:{str(e)}\n"
165
-
166
- # 打包当前截图
167
- yield "### 打包当前截图..."
168
- try:
169
- screenshot = device.screenshot()
170
- img = cv2.imencode('.png', screenshot)[1].tobytes()
171
- zipf.writestr('current_screenshot.png', img)
172
- except Exception as e:
173
- error += f"保存当前截图失败:{str(e)}\n"
174
-
175
- # 打包配置文件
176
- yield "### 打包配置文件..."
177
- try:
178
- with open('config.json', 'r', encoding='utf-8') as f:
179
- zipf.writestr('config.json', f.read())
180
- except Exception as e:
181
- error += f"保存配置文件失败:{str(e)}\n"
182
-
183
- # 打包 logs 文件夹
184
- if os.path.exists('logs'):
185
- for root, dirs, files in os.walk('logs'):
186
- for file in files:
187
- file_path = os.path.join(root, file)
188
- arcname = os.path.join('logs', os.path.relpath(file_path, 'logs'))
189
- zipf.write(file_path, arcname)
190
- yield f"### 打包 log 文件:{arcname}"
191
-
192
- # 打包 conf 文件夹
193
- if os.path.exists('conf'):
194
- for root, dirs, files in os.walk('conf'):
195
- for file in files:
196
- file_path = os.path.join(root, file)
197
- arcname = os.path.join('conf', os.path.relpath(file_path, 'conf'))
198
- zipf.write(file_path, arcname)
199
- yield f"### 打包配置文件:{arcname}"
200
-
201
- # 写出版本号
202
- zipf.writestr('version.txt', version)
203
-
204
- if not upload:
205
- yield f"### 报告已保存至 {os.path.abspath(path)}"
206
- return path
207
-
208
- # 上传报告
209
- from kotonebot.ui.file_host.sensio import upload as upload_file
210
- yield "### 上传报告..."
211
- url = ''
212
- try:
213
- url = upload_file(path)
214
- except Exception as e:
215
- yield f"### 上传报告失败:{str(e)}\n\n"
216
- return ''
217
-
218
- final_msg = f"### 报告导出成功:{url}\n\n"
219
- expire_time = datetime.now() + timedelta(days=7)
220
- if error:
221
- final_msg += "### 但发生了以下错误\n\n"
222
- final_msg += '\n* '.join(error.strip().split('\n'))
223
- final_msg += '\n'
224
- final_msg += f"### 此链接将于 {expire_time.strftime('%Y-%m-%d %H:%M:%S')}(7 天后)过期\n\n"
225
- final_msg += '### 复制以上文本并反馈给开发者'
226
- yield final_msg
227
- return path
228
-
229
112
  class KotoneBotUI:
230
113
  def __init__(self, kaa: Kaa) -> None:
231
114
  self.is_running: bool = False
@@ -234,6 +117,8 @@ class KotoneBotUI:
234
117
  self.is_single_task_stopping: bool = False # 新增:标记单个任务是否正在停止
235
118
  self._kaa = kaa
236
119
  self._load_config()
120
+ self.update_service = UpdateService()
121
+ self.feedback_service = FeedbackService()
237
122
  # IdleModeManager 空闲检测
238
123
  def safe_get_is_running():
239
124
  try:
@@ -1530,6 +1415,14 @@ class KotoneBotUI:
1530
1415
  info=ProduceConfig.model_fields['produce_timeout_cd'].description
1531
1416
  )
1532
1417
 
1418
+ interrupt_timeout = gr.Number(
1419
+ minimum=20,
1420
+ value=self.current_config.options.produce.interrupt_timeout,
1421
+ label="检测超时时间",
1422
+ interactive=True,
1423
+ info=ProduceConfig.model_fields['interrupt_timeout'].description
1424
+ )
1425
+
1533
1426
  enable_fever_month = gr.Radio(
1534
1427
  label="自动启用强化月间",
1535
1428
  choices=[("不操作", "ignore"), ("自动启用", "on"), ("自动禁用", "off")],
@@ -1556,6 +1449,7 @@ class KotoneBotUI:
1556
1449
  config.produce.selected_solution_id = data.get('selected_solution_id')
1557
1450
  config.produce.produce_count = data.get('produce_count', 1)
1558
1451
  config.produce.produce_timeout_cd = data.get('produce_timeout_cd', 60)
1452
+ config.produce.interrupt_timeout = data.get('interrupt_timeout', 180)
1559
1453
  config.produce.enable_fever_month = data.get('enable_fever_month', 'ignore')
1560
1454
 
1561
1455
  return set_config, {
@@ -1563,6 +1457,7 @@ class KotoneBotUI:
1563
1457
  'selected_solution_id': solution_dropdown,
1564
1458
  'produce_count': produce_count,
1565
1459
  'produce_timeout_cd': produce_timeout_cd,
1460
+ 'interrupt_timeout': interrupt_timeout,
1566
1461
  'enable_fever_month': enable_fever_month
1567
1462
  }
1568
1463
 
@@ -2452,6 +2347,16 @@ class KotoneBotUI:
2452
2347
  info=MiscConfig.model_fields['update_channel'].description,
2453
2348
  interactive=True
2454
2349
  )
2350
+ log_level = gr.Dropdown(
2351
+ choices=[
2352
+ ("调试", "debug"),
2353
+ ("详细", "verbose")
2354
+ ],
2355
+ value=self.current_config.options.misc.log_level,
2356
+ label="日志等级",
2357
+ info=MiscConfig.model_fields['log_level'].description,
2358
+ interactive=True
2359
+ )
2455
2360
  with gr.Row():
2456
2361
  gr.Button("创建桌面快捷方式").click(
2457
2362
  fn=self._create_shortcut_button_click(False),
@@ -2467,12 +2372,14 @@ class KotoneBotUI:
2467
2372
  config.misc.auto_install_update = data['auto_install_update']
2468
2373
  config.misc.expose_to_lan = data['expose_to_lan']
2469
2374
  config.misc.update_channel = data['update_channel']
2375
+ config.misc.log_level = data['log_level']
2470
2376
 
2471
2377
  return set_config, {
2472
2378
  'check_update': check_update,
2473
2379
  'auto_install_update': auto_install_update,
2474
2380
  'expose_to_lan': expose_to_lan,
2475
- 'update_channel': update_channel
2381
+ 'update_channel': update_channel,
2382
+ 'log_level': log_level
2476
2383
  }
2477
2384
 
2478
2385
  def _create_shortcut_button_click(self, start_immediately: bool) -> Callable[[], None]:
@@ -2644,19 +2551,43 @@ class KotoneBotUI:
2644
2551
 
2645
2552
  result_text = gr.Markdown("等待操作\n\n\n")
2646
2553
 
2647
- def on_upload_click(title: str, description: str):
2648
- yield from _save_bug_report(title, description, self._kaa.version, upload=True)
2554
+ def create_report(title: str, description: str, upload: bool, progress=gr.Progress()):
2555
+
2556
+ def on_progress(data: Dict[str, Any]):
2557
+ progress_val = data['step'] / data['total_steps']
2558
+ if data['type'] == 'packing':
2559
+ desc = f"({data['step']}/{data['total_steps']}) 正在打包 {data['item']}"
2560
+ elif data['type'] == 'uploading':
2561
+ desc = f"({data['step']}/{data['total_steps']}) 正在上传 {data['item']}"
2562
+ elif data['type'] == 'done':
2563
+ if 'url' in data:
2564
+ desc = "上传完成"
2565
+ else:
2566
+ desc = "已保存至本地"
2567
+ else:
2568
+ desc = "正在处理..."
2569
+ progress(progress_val, desc=desc)
2649
2570
 
2650
- def on_save_local_click(title: str, description: str):
2651
- yield from _save_bug_report(title, description, self._kaa.version, upload=False)
2571
+ try:
2572
+ result = self.feedback_service.report(
2573
+ title=title,
2574
+ description=description,
2575
+ version=self._kaa.version,
2576
+ upload=upload,
2577
+ on_progress=on_progress
2578
+ )
2579
+ return result.message
2580
+ except FeedbackServiceError as e:
2581
+ gr.Error(str(e))
2582
+ return f"### 操作失败\n\n{e}"
2652
2583
 
2653
2584
  upload_report_btn.click(
2654
- fn=on_upload_click,
2585
+ fn=partial(create_report, upload=True),
2655
2586
  inputs=[report_title, report_description],
2656
2587
  outputs=[result_text]
2657
2588
  )
2658
2589
  save_local_report_btn.click(
2659
- fn=on_save_local_click,
2590
+ fn=partial(create_report, upload=False),
2660
2591
  inputs=[report_title, report_description],
2661
2592
  outputs=[result_text]
2662
2593
  )
@@ -2666,18 +2597,12 @@ class KotoneBotUI:
2666
2597
  with gr.Tab("更新"):
2667
2598
  gr.Markdown("## 版本管理")
2668
2599
 
2669
- # 更新日志
2670
2600
  with gr.Accordion("更新日志", open=False):
2671
2601
  from kaa.metadata import WHATS_NEW
2672
2602
  gr.Markdown(WHATS_NEW)
2673
2603
 
2674
- # 载入信息按钮
2675
2604
  load_info_btn = gr.Button("载入信息", variant="primary")
2676
-
2677
- # 状态信息
2678
2605
  status_text = gr.Markdown("")
2679
-
2680
- # 版本选择下拉框(用于安装)
2681
2606
  version_dropdown = gr.Dropdown(
2682
2607
  label="选择要安装的版本",
2683
2608
  choices=[],
@@ -2685,405 +2610,71 @@ class KotoneBotUI:
2685
2610
  visible=False,
2686
2611
  interactive=True
2687
2612
  )
2688
-
2689
- # 安装选定版本按钮
2690
2613
  install_selected_btn = gr.Button("安装选定版本", visible=False)
2691
2614
 
2692
- def list_all_versions():
2693
- """列出所有可用版本"""
2694
- import logging
2695
- import re
2696
- logger = logging.getLogger(__name__)
2697
-
2698
- # 检查启动器版本
2699
- def check_launcher_version():
2700
- """通过读取bootstrap.pyz/meta.py获取启动器版本"""
2701
- import zipfile
2702
- try:
2703
- bootstrap_path = os.path.join(os.getcwd(), "bootstrap.pyz")
2704
- if not os.path.exists(bootstrap_path):
2705
- logger.warning("启动器文件不存在")
2706
- gr.Warning("启动器文件不存在")
2707
- return None
2708
-
2709
- # 尝试从bootstrap.pyz中读取meta.py
2710
- try:
2711
- with zipfile.ZipFile(bootstrap_path, 'r') as zip_file:
2712
- if 'meta.py' in zip_file.namelist():
2713
- # 读取meta.py内容
2714
- meta_content = zip_file.read('meta.py').decode('utf-8')
2715
-
2716
- # 创建一个安全的执行环境
2717
- exec_globals = {}
2718
- exec_locals = {}
2719
-
2720
- # 执行meta.py内容
2721
- exec(meta_content, exec_globals, exec_locals)
2722
-
2723
- # 获取VERSION变量
2724
- if 'VERSION' in exec_locals:
2725
- version = exec_locals['VERSION']
2726
- # 移除v前缀(如果有)
2727
- if isinstance(version, str) and version.startswith('v'):
2728
- version = version[1:]
2729
- logger.info(f"从meta.py读取到启动器版本: {version}")
2730
- return str(version)
2731
- else:
2732
- logger.warning("meta.py中未找到VERSION变量")
2733
- gr.Warning("meta.py中未找到VERSION变量")
2734
- return None
2735
- else:
2736
- logger.warning("bootstrap.pyz中未找到meta.py文件")
2737
- gr.Warning("bootstrap.pyz中未找到meta.py文件")
2738
- return None
2739
- except zipfile.BadZipFile:
2740
- # 不是有效的zip文件,可能是旧版本启动器
2741
- logger.info("bootstrap.pyz不是有效的zip文件,判断为旧版本启动器")
2742
- return "0.4.x"
2743
- except Exception as e:
2744
- logger.warning(f"读取bootstrap.pyz失败: {str(e)}")
2745
- gr.Warning(f"读取bootstrap.pyz失败: {str(e)}")
2746
- return None
2747
-
2748
- except Exception as e:
2749
- logger.warning(f"检查启动器版本失败: {str(e)}")
2750
- gr.Warning(f"检查启动器版本失败: {str(e)}")
2751
- return None
2752
-
2615
+ def on_load_info():
2616
+ """使用 UpdateService 加载版本信息。"""
2617
+ yield (
2618
+ "正在载入版本信息...",
2619
+ gr.Button(value="载入中...", interactive=False),
2620
+ gr.Dropdown(visible=False),
2621
+ gr.Button(visible=False)
2622
+ )
2753
2623
  try:
2754
- # 构建命令,使用清华镜像源
2755
- cmd = [
2756
- sys.executable, "-m", "pip", "index", "versions", "ksaa", "--json", "--pre",
2757
- "--index-url", "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple",
2758
- "--trusted-host", "mirrors.tuna.tsinghua.edu.cn"
2759
- ]
2760
- logger.info(f"执行命令: {' '.join(cmd)}")
2761
-
2762
- # 使用 pip index versions --json 来获取版本信息
2763
- result = subprocess.run(
2764
- cmd,
2765
- capture_output=True,
2766
- text=True,
2767
- timeout=30
2768
- )
2769
-
2770
- logger.info(f"命令返回码: {result.returncode}")
2771
- if result.stdout:
2772
- logger.info(f"命令输出: {result.stdout[:500]}...") # 只记录前500字符
2773
- if result.stderr:
2774
- logger.warning(f"命令错误输出: {result.stderr}")
2775
-
2776
- if result.returncode != 0:
2777
- error_msg = f"获取版本列表失败: {result.stderr}"
2778
- logger.error(error_msg)
2779
- return (
2780
- error_msg,
2781
- gr.Button(value="载入信息", interactive=True),
2782
- gr.Dropdown(visible=False),
2783
- gr.Button(visible=False)
2784
- )
2785
-
2786
- # 解析 JSON 输出
2787
- try:
2788
- data = json.loads(result.stdout)
2789
- versions = data.get("versions", [])
2790
- latest_version = data.get("latest", "")
2791
- installed_version = data.get("installed_version", "")
2792
-
2793
- logger.info(f"解析到 {len(versions)} 个版本")
2794
- logger.info(f"最新版本: {latest_version}")
2795
- logger.info(f"已安装版本: {installed_version}")
2796
-
2797
- except json.JSONDecodeError as e:
2798
- error_msg = f"解析版本信息失败: {str(e)}"
2799
- logger.error(error_msg)
2800
- return (
2801
- error_msg,
2802
- gr.Button(value="载入信息", interactive=True),
2803
- gr.Dropdown(visible=False),
2804
- gr.Button(visible=False)
2805
- )
2806
-
2807
- if not versions:
2808
- error_msg = "未找到可用版本"
2809
- logger.warning(error_msg)
2810
- return (
2811
- error_msg,
2812
- gr.Button(value="载入信息", interactive=True),
2813
- gr.Dropdown(visible=False),
2814
- gr.Button(visible=False)
2815
- )
2816
-
2817
- # 检查启动器版本
2818
- launcher_version = check_launcher_version()
2819
-
2820
- # 构建状态信息
2821
- status_info = []
2822
- if installed_version:
2823
- status_info.append(f"**当前安装版本:** {installed_version}")
2824
- if latest_version:
2825
- status_info.append(f"**最新版本:** {latest_version}")
2826
- if launcher_version:
2827
- if launcher_version == "0.4.x":
2828
- status_info.append(f"**启动器版本:** < v0.5.0 (旧版本)")
2829
- else:
2830
- status_info.append(f"**启动器版本:** v{launcher_version}")
2831
- else:
2832
- status_info.append(f"**启动器版本:** 未知")
2833
- status_info.append(f"**找到 {len(versions)} 个可用版本**")
2834
-
2835
- status_message = "\n\n".join(status_info)
2836
- logger.info(f"版本信息载入完成: {status_message}")
2837
-
2838
- # 返回更新后的组件
2839
- return (
2840
- status_message,
2841
- gr.Button(value="载入信息", interactive=True),
2842
- gr.Dropdown(choices=versions, value=versions[0] if versions else None, visible=True, label="选择要安装的版本"),
2843
- gr.Button(visible=True, value="安装选定版本")
2844
- )
2845
-
2846
- except subprocess.TimeoutExpired:
2847
- error_msg = "获取版本列表超时"
2848
- logger.error(error_msg)
2849
- return (
2850
- error_msg,
2851
- gr.Button(value="载入信息", interactive=True),
2852
- gr.Dropdown(visible=False),
2853
- gr.Button(visible=False)
2854
- )
2855
- except Exception as e:
2856
- error_msg = f"获取版本列表失败: {str(e)}"
2857
- logger.error(error_msg)
2858
- return (
2859
- error_msg,
2624
+ versions_data = self.update_service.list_remote_versions()
2625
+ except UpdateFetchListError as e:
2626
+ gr.Error(str(e))
2627
+ yield (
2628
+ str(e),
2860
2629
  gr.Button(value="载入信息", interactive=True),
2861
2630
  gr.Dropdown(visible=False),
2862
2631
  gr.Button(visible=False)
2863
2632
  )
2633
+ return
2864
2634
 
2865
- def install_selected_version(selected_version: str):
2866
- """安装选定的版本"""
2867
- import logging
2868
- import threading
2869
- import time
2870
- import re
2871
- logger = logging.getLogger(__name__)
2872
-
2873
- if not selected_version:
2874
- error_msg = "请先选择一个版本"
2875
- logger.warning(error_msg)
2876
- return error_msg
2877
-
2878
-
2879
- def compare_version(version1: str, version2: str) -> int:
2880
- """比较版本号,返回-1(v1<v2), 0(v1==v2), 1(v1>v2)"""
2881
- # 处理特殊标记
2882
- if version1 == "0.4.x":
2883
- version1 = "0.4.0"
2884
-
2885
- def parse_version(v):
2886
- # 移除v前缀并解析版本号和预发布标识
2887
- v = v.lstrip('v')
2888
- if 'b' in v:
2889
- base, beta = v.split('b', 1)
2890
- return tuple(map(int, base.split('.'))) + (-1, int(beta))
2891
- elif 'a' in v:
2892
- base, alpha = v.split('a', 1)
2893
- return tuple(map(int, base.split('.'))) + (-2, int(alpha))
2894
- elif 'rc' in v:
2895
- base, rc = v.split('rc', 1)
2896
- return tuple(map(int, base.split('.'))) + (-0.5, int(rc))
2897
- else:
2898
- return tuple(map(int, v.split('.'))) + (0, 0)
2899
-
2900
- v1_parsed = parse_version(version1)
2901
- v2_parsed = parse_version(version2)
2902
-
2903
- if v1_parsed < v2_parsed:
2904
- return -1
2905
- elif v1_parsed > v2_parsed:
2906
- return 1
2635
+ status_info = [
2636
+ f"**当前安装版本:** {versions_data.installed_version or '未知'}",
2637
+ f"**最新版本:** {versions_data.latest or '未知'}",
2638
+ ]
2639
+ if versions_data.launcher_version:
2640
+ if versions_data.launcher_version == "0.4.x":
2641
+ status_info.append("**启动器版本:** < v0.5.0 (旧版本)")
2907
2642
  else:
2908
- return 0
2909
-
2910
- # 检查启动器版本进行兼容性验证
2911
- def check_launcher_version_simple():
2912
- """通过读取bootstrap.pyz/meta.py获取启动器版本"""
2913
- import zipfile
2914
- try:
2915
- bootstrap_path = os.path.join(os.getcwd(), "bootstrap.pyz")
2916
- if not os.path.exists(bootstrap_path):
2917
- logger.warning("启动器文件不存在")
2918
- gr.Warning("启动器文件不存在")
2919
- return None
2920
-
2921
- # 尝试从bootstrap.pyz中读取meta.py
2922
- try:
2923
- with zipfile.ZipFile(bootstrap_path, 'r') as zip_file:
2924
- if 'meta.py' in zip_file.namelist():
2925
- # 读取meta.py内容
2926
- meta_content = zip_file.read('meta.py').decode('utf-8')
2927
-
2928
- # 创建一个安全的执行环境
2929
- exec_globals = {}
2930
- exec_locals = {}
2931
-
2932
- # 执行meta.py内容
2933
- exec(meta_content, exec_globals, exec_locals)
2934
-
2935
- # 获取VERSION变量
2936
- if 'VERSION' in exec_locals:
2937
- version = exec_locals['VERSION']
2938
- # 移除v前缀(如果有)
2939
- if isinstance(version, str) and version.startswith('v'):
2940
- version = version[1:]
2941
- logger.info(f"从meta.py读取到启动器版本: {version}")
2942
- return str(version)
2943
- else:
2944
- logger.warning("meta.py中未找到VERSION变量")
2945
- gr.Warning("meta.py中未找到VERSION变量")
2946
- return None
2947
- else:
2948
- logger.warning("bootstrap.pyz中未找到meta.py文件")
2949
- gr.Warning("bootstrap.pyz中未找到meta.py文件")
2950
- return None
2951
- except zipfile.BadZipFile:
2952
- # 不是有效的zip文件,可能是旧版本启动器
2953
- logger.info("bootstrap.pyz不是有效的zip文件,判断为旧版本启动器")
2954
- return "0.4.x"
2955
- except Exception as e:
2956
- logger.warning(f"读取bootstrap.pyz失败: {str(e)}")
2957
- gr.Warning(f"读取bootstrap.pyz失败: {str(e)}")
2958
- return None
2959
-
2960
- except Exception as e:
2961
- logger.warning(f"检查启动器版本失败: {str(e)}")
2962
- gr.Warning(f"检查启动器版本失败: {str(e)}")
2963
- return None
2964
-
2965
- # 执行启动器版本检查
2966
- launcher_version = check_launcher_version_simple()
2967
- logger.info(f"检测到启动器版本: {launcher_version}")
2968
-
2969
- # 版本兼容性检查
2970
- if launcher_version:
2971
- if compare_version(launcher_version, "0.5.0") < 0:
2972
- # 启动器版本低于0.5.0
2973
- logger.warning(f"启动器版本 {launcher_version} 低于 v0.5.0")
2974
-
2975
- # 检查要安装的版本是否 >= v2025.9b1
2976
- if compare_version(selected_version, "2025.9b1") >= 0:
2977
- error_msg = (
2978
- f"❌ 版本兼容性错误\n\n"
2979
- f"启动器版本: {launcher_version}\n"
2980
- f"要安装的版本: {selected_version}\n\n"
2981
- f"v2025.9b1 及以上版本需要**启动器 v0.5.0*** 或更高版本支持。\n"
2982
- f"请先升级启动器到 v0.5.0 以上版本。[查看帮助](https://www.kdocs.cn/l/cetCY8mGKHLj?linkname=UhPH1itaSv)"
2983
- )
2984
- logger.error(error_msg)
2985
- return error_msg
2986
- else:
2987
- # 版本兼容,但给出警告
2988
- logger.warning(f"启动器版本较低,建议升级到 v0.5.0 以上")
2989
- gr.Warning("启动器版本较低,建议升级到 v0.5.0 以上")
2643
+ status_info.append(f"**启动器版本:** v{versions_data.launcher_version}")
2990
2644
  else:
2991
- # 无法获取启动器版本,给出警告但继续
2992
- logger.warning("无法获取启动器版本,可以继续安装但可能存在兼容性问题")
2993
- gr.Warning("无法获取启动器版本,可以继续安装但可能存在兼容性问题")
2994
-
2995
- def install_and_exit():
2996
- """在后台线程中执行安装并退出程序"""
2997
- try:
2998
- # 等待一小段时间确保UI响应已返回
2999
- time.sleep(1)
3000
-
3001
- # 构建启动器命令
3002
- bootstrap_path = os.path.join(os.getcwd(), "bootstrap.pyz")
3003
- cmd = [sys.executable, bootstrap_path, f"--install-version={selected_version}"]
3004
- logger.info(f"开始通过启动器安装版本 {selected_version}")
3005
- logger.info(f"执行命令: {' '.join(cmd)}")
3006
-
3007
- # 启动启动器进程(不等待完成)
3008
- subprocess.Popen(
3009
- cmd,
3010
- cwd=os.getcwd(),
3011
- creationflags=subprocess.CREATE_NEW_CONSOLE if os.name == 'nt' else 0
3012
- )
3013
-
3014
- # 退出当前程序
3015
- logger.info("安装即将开始,正在退出当前程序...")
3016
- os._exit(0)
3017
-
3018
- except Exception as e:
3019
- raise
3020
-
3021
- try:
3022
- # 在后台线程中执行安装和退出
3023
- install_thread = threading.Thread(target=install_and_exit, daemon=True)
3024
- install_thread.start()
3025
-
3026
- return f"正在启动器中安装版本 {selected_version},程序将自动重启..."
3027
-
3028
- except Exception as e:
3029
- error_msg = f"启动安装进程失败: {str(e)}"
3030
- logger.error(error_msg)
3031
- return error_msg
3032
-
3033
- def load_info_with_button_state():
3034
- """载入信息并管理按钮状态"""
3035
- import logging
3036
- logger = logging.getLogger(__name__)
3037
-
3038
- logger.info("开始载入版本信息")
2645
+ status_info.append("**启动器版本:** 未知")
2646
+
2647
+ status_info.append(f"**找到 {len(versions_data.versions)} 个可用版本**")
2648
+ status_message = "\n\n".join(status_info)
3039
2649
 
3040
- # 先禁用按钮
3041
2650
  yield (
3042
- "正在载入版本信息...",
3043
- gr.Button(value="载入中...", interactive=False),
3044
- gr.Dropdown(visible=False),
3045
- gr.Button(visible=False)
2651
+ status_message,
2652
+ gr.Button(value="载入信息", interactive=True),
2653
+ gr.Dropdown(choices=versions_data.versions, value=versions_data.versions[0] if versions_data.versions else None, visible=True),
2654
+ gr.Button(visible=True)
3046
2655
  )
3047
2656
 
3048
- # 执行载入操作
3049
- result = list_all_versions()
3050
- logger.info("版本信息载入操作完成")
3051
- yield result
2657
+ def on_install_selected(selected_version: str):
2658
+ """使用 UpdateService 安装所选版本。"""
2659
+ if not selected_version:
2660
+ gr.Warning("请先选择一个版本。")
2661
+ return
2662
+
2663
+ try:
2664
+ self.update_service.install_version(selected_version)
2665
+ gr.Info(f"正在启动器中安装版本 {selected_version},程序将自动重启...")
2666
+ except UpdateServiceError as e:
2667
+ gr.Error(str(e))
3052
2668
 
3053
- # 绑定事件
3054
2669
  load_info_btn.click(
3055
- fn=load_info_with_button_state,
2670
+ fn=on_load_info,
3056
2671
  outputs=[status_text, load_info_btn, version_dropdown, install_selected_btn]
3057
2672
  )
3058
2673
 
3059
2674
  install_selected_btn.click(
3060
- fn=install_selected_version,
2675
+ fn=on_install_selected,
3061
2676
  inputs=[version_dropdown],
3062
- outputs=[status_text]
3063
- )
3064
-
3065
- def _create_screen_tab(self) -> None:
3066
- with gr.Tab("画面"):
3067
- gr.Markdown("## 当前设备画面")
3068
- refresh_btn = gr.Button("刷新画面", variant="primary")
3069
- WIDTH = 720 // 3
3070
- HEIGHT = 1280 // 3
3071
- last_update_text = gr.Markdown("上次更新时间:无数据")
3072
- screenshot_display = gr.Image(type="numpy", width=WIDTH, height=HEIGHT)
3073
-
3074
- def update_screenshot():
3075
- ctx = ContextStackVars.current()
3076
- if ctx is None:
3077
- return [None, "上次更新时间:无上下文数据"]
3078
- screenshot = ctx._screenshot
3079
- if screenshot is None:
3080
- return [None, "上次更新时间:无截图数据"]
3081
- screenshot = cv2.cvtColor(screenshot, cv2.COLOR_BGR2RGB)
3082
- return screenshot, f"上次更新时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
3083
-
3084
- refresh_btn.click(
3085
- fn=update_screenshot,
3086
- outputs=[screenshot_display, last_update_text]
2677
+ outputs=[]
3087
2678
  )
3088
2679
 
3089
2680
  def _load_config(self) -> None:
@@ -3128,7 +2719,6 @@ class KotoneBotUI:
3128
2719
  self._create_produce_tab()
3129
2720
  self._create_log_tab()
3130
2721
  self._create_whats_new_tab()
3131
- self._create_screen_tab()
3132
2722
 
3133
2723
  # 启动 IdleModeManager 后台线程
3134
2724
  self.idle_mgr.start()