synth-ai 0.2.14__py3-none-any.whl → 0.4.4__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.

Potentially problematic release.


This version of synth-ai might be problematic. Click here for more details.

Files changed (1086) hide show
  1. synth_ai/__init__.py +25 -46
  2. synth_ai/__main__.py +30 -3
  3. synth_ai/cli/__init__.py +98 -72
  4. synth_ai/cli/__main__.py +42 -0
  5. synth_ai/cli/_internal/__init__.py +5 -0
  6. synth_ai/cli/_internal/modal_wrapper.py +31 -0
  7. synth_ai/cli/_internal/storage.py +20 -0
  8. synth_ai/cli/_internal/typer_patch.py +47 -0
  9. synth_ai/cli/_internal/validate_task_app.py +29 -0
  10. synth_ai/cli/agents/__init__.py +17 -0
  11. synth_ai/cli/agents/claude.py +77 -0
  12. synth_ai/cli/agents/codex.py +265 -0
  13. synth_ai/cli/agents/opencode.py +253 -0
  14. synth_ai/cli/commands/__init__.py +18 -0
  15. synth_ai/cli/commands/artifacts/__init__.py +13 -0
  16. synth_ai/cli/commands/artifacts/client.py +119 -0
  17. synth_ai/cli/commands/artifacts/config.py +57 -0
  18. synth_ai/cli/commands/artifacts/core.py +24 -0
  19. synth_ai/cli/commands/artifacts/download.py +188 -0
  20. synth_ai/cli/commands/artifacts/export.py +186 -0
  21. synth_ai/cli/commands/artifacts/list.py +156 -0
  22. synth_ai/cli/commands/artifacts/parsing.py +250 -0
  23. synth_ai/cli/commands/artifacts/show.py +336 -0
  24. synth_ai/cli/commands/demo/__init__.py +3 -0
  25. synth_ai/cli/commands/demo/core.py +153 -0
  26. synth_ai/cli/commands/eval/__init__.py +10 -0
  27. synth_ai/cli/commands/eval/config.py +338 -0
  28. synth_ai/cli/commands/eval/core.py +258 -0
  29. synth_ai/cli/commands/eval/runner.py +704 -0
  30. synth_ai/cli/commands/eval/validation.py +60 -0
  31. synth_ai/cli/commands/filter/__init__.py +12 -0
  32. synth_ai/cli/commands/filter/core.py +424 -0
  33. synth_ai/cli/commands/filter/errors.py +55 -0
  34. synth_ai/cli/commands/filter/validation.py +77 -0
  35. synth_ai/cli/commands/help/__init__.py +185 -0
  36. synth_ai/cli/commands/help/core.py +72 -0
  37. synth_ai/cli/commands/scan/__init__.py +19 -0
  38. synth_ai/cli/commands/scan/cloudflare_scanner.py +403 -0
  39. synth_ai/cli/commands/scan/core.py +344 -0
  40. synth_ai/cli/commands/scan/health_checker.py +242 -0
  41. synth_ai/cli/commands/scan/local_scanner.py +278 -0
  42. synth_ai/cli/commands/scan/models.py +83 -0
  43. synth_ai/cli/commands/smoke/__init__.py +7 -0
  44. synth_ai/cli/commands/smoke/core.py +1428 -0
  45. synth_ai/cli/commands/status/__init__.py +3 -0
  46. synth_ai/cli/commands/status/client.py +91 -0
  47. synth_ai/cli/commands/status/config.py +12 -0
  48. synth_ai/cli/commands/status/errors.py +11 -0
  49. synth_ai/cli/commands/status/subcommands/__init__.py +3 -0
  50. synth_ai/cli/commands/status/subcommands/config.py +13 -0
  51. synth_ai/cli/commands/status/subcommands/files.py +34 -0
  52. synth_ai/cli/commands/status/subcommands/jobs.py +51 -0
  53. synth_ai/cli/commands/status/subcommands/models.py +35 -0
  54. synth_ai/cli/commands/status/subcommands/runs.py +34 -0
  55. synth_ai/cli/commands/status/subcommands/session.py +77 -0
  56. synth_ai/cli/commands/status/subcommands/summary.py +39 -0
  57. synth_ai/cli/commands/status/subcommands/utils.py +41 -0
  58. synth_ai/cli/commands/status/utils.py +23 -0
  59. synth_ai/cli/commands/train/__init__.py +51 -0
  60. synth_ai/cli/commands/train/core.py +22 -0
  61. synth_ai/cli/commands/train/errors.py +117 -0
  62. synth_ai/cli/commands/train/prompt_learning_validation.py +632 -0
  63. synth_ai/cli/commands/train/validation.py +392 -0
  64. synth_ai/cli/commands/train/verifier_schemas.py +200 -0
  65. synth_ai/cli/commands/train/verifier_validation.py +235 -0
  66. synth_ai/cli/demo_apps/__init__.py +10 -0
  67. synth_ai/cli/demo_apps/core/__init__.py +28 -0
  68. synth_ai/cli/demo_apps/core/cli.py +1735 -0
  69. synth_ai/cli/demo_apps/crafter/crafter_fft_4b.toml +55 -0
  70. synth_ai/cli/demo_apps/crafter/grpo_crafter_task_app.py +186 -0
  71. synth_ai/cli/demo_apps/crafter/rl_from_base_qwen4b.toml +74 -0
  72. synth_ai/cli/demo_apps/demo_registry.py +176 -0
  73. synth_ai/cli/demo_apps/demo_task_apps/core.py +440 -0
  74. synth_ai/cli/demo_apps/demo_task_apps/crafter/__init__.py +1 -0
  75. synth_ai/cli/demo_apps/demo_task_apps/crafter/grpo_crafter_task_app.py +185 -0
  76. synth_ai/cli/demo_apps/demo_task_apps/math/config.toml +73 -0
  77. synth_ai/cli/demo_apps/demo_task_apps/math/modal_task_app.py +738 -0
  78. synth_ai/cli/demo_apps/demo_task_apps/math/task_app_entry.py +39 -0
  79. synth_ai/cli/demo_apps/math/__init__.py +1 -0
  80. synth_ai/cli/demo_apps/math/_common.py +16 -0
  81. synth_ai/cli/demo_apps/math/app.py +38 -0
  82. synth_ai/cli/demo_apps/math/config.toml +75 -0
  83. synth_ai/cli/demo_apps/math/deploy_modal.py +54 -0
  84. synth_ai/cli/demo_apps/math/modal_task_app.py +698 -0
  85. synth_ai/cli/demo_apps/math/task_app_entry.py +53 -0
  86. synth_ai/cli/demo_apps/mipro/main.py +271 -0
  87. synth_ai/cli/demo_apps/mipro/task_app.py +911 -0
  88. synth_ai/cli/demo_apps/mipro/train_cfg.toml +92 -0
  89. synth_ai/cli/demos/__init__.py +12 -0
  90. synth_ai/cli/demos/demo.py +32 -0
  91. synth_ai/cli/demos/rl_demo.py +254 -0
  92. synth_ai/cli/deploy.py +216 -0
  93. synth_ai/cli/infra/__init__.py +14 -0
  94. synth_ai/cli/infra/balance.py +216 -0
  95. synth_ai/cli/infra/mcp.py +35 -0
  96. synth_ai/cli/infra/modal_app.py +36 -0
  97. synth_ai/cli/infra/setup.py +69 -0
  98. synth_ai/cli/infra/status.py +16 -0
  99. synth_ai/cli/infra/turso.py +77 -0
  100. synth_ai/cli/lib/__init__.py +10 -0
  101. synth_ai/cli/lib/agents.py +76 -0
  102. synth_ai/cli/lib/apps/modal_app.py +101 -0
  103. synth_ai/cli/lib/apps/task_app.py +642 -0
  104. synth_ai/cli/lib/bin.py +39 -0
  105. synth_ai/cli/lib/env.py +375 -0
  106. synth_ai/cli/lib/errors.py +85 -0
  107. synth_ai/cli/lib/modal.py +315 -0
  108. synth_ai/cli/lib/plotting.py +126 -0
  109. synth_ai/cli/lib/prompt_args.py +39 -0
  110. synth_ai/cli/lib/prompts.py +284 -0
  111. synth_ai/cli/lib/sqld.py +122 -0
  112. synth_ai/cli/lib/task_app_discovery.py +884 -0
  113. synth_ai/cli/lib/task_app_env.py +295 -0
  114. synth_ai/cli/lib/train_cfgs.py +300 -0
  115. synth_ai/cli/lib/tunnel_records.py +207 -0
  116. synth_ai/cli/local/__init__.py +14 -0
  117. synth_ai/cli/local/experiment_queue/__init__.py +72 -0
  118. synth_ai/cli/local/experiment_queue/api_schemas.py +221 -0
  119. synth_ai/cli/local/experiment_queue/celery_app.py +208 -0
  120. synth_ai/cli/local/experiment_queue/config.py +128 -0
  121. synth_ai/cli/local/experiment_queue/config_utils.py +272 -0
  122. synth_ai/cli/local/experiment_queue/database.py +175 -0
  123. synth_ai/cli/local/experiment_queue/dispatcher.py +119 -0
  124. synth_ai/cli/local/experiment_queue/models.py +231 -0
  125. synth_ai/cli/local/experiment_queue/progress_info.py +160 -0
  126. synth_ai/cli/local/experiment_queue/results.py +373 -0
  127. synth_ai/cli/local/experiment_queue/schemas.py +131 -0
  128. synth_ai/cli/local/experiment_queue/service.py +344 -0
  129. synth_ai/cli/local/experiment_queue/status.py +372 -0
  130. synth_ai/cli/local/experiment_queue/status_tracker.py +360 -0
  131. synth_ai/cli/local/experiment_queue/tasks.py +1984 -0
  132. synth_ai/cli/local/experiment_queue/trace_storage.py +65 -0
  133. synth_ai/cli/local/experiment_queue/validation.py +157 -0
  134. synth_ai/cli/local/session/__init__.py +92 -0
  135. synth_ai/cli/local/session/client.py +383 -0
  136. synth_ai/cli/local/session/constants.py +63 -0
  137. synth_ai/cli/local/session/exceptions.py +105 -0
  138. synth_ai/cli/local/session/manager.py +139 -0
  139. synth_ai/cli/local/session/models.py +89 -0
  140. synth_ai/cli/local/session/query.py +110 -0
  141. synth_ai/cli/root.py +30 -6
  142. synth_ai/cli/task_apps/__init__.py +37 -0
  143. synth_ai/cli/task_apps/commands.py +3145 -0
  144. synth_ai/cli/task_apps/deploy.py +7 -0
  145. synth_ai/cli/task_apps/list.py +26 -0
  146. synth_ai/cli/task_apps/main.py +36 -0
  147. synth_ai/cli/task_apps/modal_serve.py +11 -0
  148. synth_ai/cli/task_apps/serve.py +11 -0
  149. synth_ai/cli/training/__init__.py +8 -0
  150. synth_ai/cli/training/train.py +5 -0
  151. synth_ai/cli/training/train_cfg.py +34 -0
  152. synth_ai/cli/training/watch.py +506 -0
  153. synth_ai/cli/turso.py +34 -55
  154. synth_ai/cli/utils/__init__.py +8 -0
  155. synth_ai/cli/utils/experiments.py +235 -0
  156. synth_ai/cli/utils/queue.py +504 -0
  157. synth_ai/cli/utils/recent.py +133 -0
  158. synth_ai/cli/utils/traces.py +164 -0
  159. synth_ai/contracts/__init__.py +67 -0
  160. synth_ai/core/__init__.py +100 -0
  161. synth_ai/core/_utils/__init__.py +54 -0
  162. synth_ai/core/_utils/base_url.py +10 -0
  163. synth_ai/core/_utils/http.py +10 -0
  164. synth_ai/core/_utils/prompts.py +14 -0
  165. synth_ai/core/_utils/task_app_state.py +12 -0
  166. synth_ai/core/_utils/user_config.py +10 -0
  167. synth_ai/core/apps/common.py +116 -0
  168. synth_ai/core/auth.py +95 -0
  169. synth_ai/core/cfgs.py +240 -0
  170. synth_ai/core/config/__init__.py +16 -0
  171. synth_ai/core/config/base.py +168 -0
  172. synth_ai/core/config/resolver.py +89 -0
  173. synth_ai/core/env.py +231 -0
  174. synth_ai/core/errors.py +125 -0
  175. synth_ai/core/http.py +230 -0
  176. synth_ai/core/integrations/__init__.py +11 -0
  177. synth_ai/core/integrations/cloudflare.py +1886 -0
  178. synth_ai/core/integrations/mcp/__init__.py +6 -0
  179. synth_ai/core/integrations/mcp/__main__.py +8 -0
  180. synth_ai/core/integrations/mcp/claude.py +36 -0
  181. synth_ai/core/integrations/mcp/main.py +254 -0
  182. synth_ai/core/integrations/mcp/setup.py +100 -0
  183. synth_ai/core/integrations/modal.py +277 -0
  184. synth_ai/core/json.py +72 -0
  185. synth_ai/core/log_filter.py +99 -0
  186. synth_ai/core/logging.py +82 -0
  187. synth_ai/core/paths.py +107 -0
  188. synth_ai/core/pricing.py +109 -0
  189. synth_ai/core/process.py +233 -0
  190. synth_ai/core/ssl.py +25 -0
  191. synth_ai/core/storage/__init__.py +71 -0
  192. synth_ai/core/task_app_state.py +318 -0
  193. synth_ai/core/telemetry.py +282 -0
  194. synth_ai/core/tracing_v3/__init__.py +99 -0
  195. synth_ai/core/tracing_v3/abstractions.py +348 -0
  196. synth_ai/core/tracing_v3/config.py +229 -0
  197. synth_ai/core/tracing_v3/constants.py +21 -0
  198. synth_ai/core/tracing_v3/db_config.py +182 -0
  199. synth_ai/core/tracing_v3/decorators.py +401 -0
  200. synth_ai/core/tracing_v3/llm_call_record_helpers.py +437 -0
  201. synth_ai/core/tracing_v3/migration_helper.py +119 -0
  202. synth_ai/core/tracing_v3/session_tracer.py +542 -0
  203. synth_ai/core/tracing_v3/storage/base.py +211 -0
  204. synth_ai/core/tracing_v3/storage/config.py +109 -0
  205. synth_ai/core/tracing_v3/storage/factory.py +39 -0
  206. synth_ai/core/tracing_v3/trace_utils.py +326 -0
  207. synth_ai/core/tracing_v3/turso/daemon.py +278 -0
  208. synth_ai/core/tracing_v3/turso/models.py +470 -0
  209. synth_ai/core/tracing_v3/turso/native_manager.py +1385 -0
  210. synth_ai/core/tracing_v3/utils.py +108 -0
  211. synth_ai/core/urls.py +18 -0
  212. synth_ai/core/user_config.py +137 -0
  213. synth_ai/core/uvicorn.py +222 -0
  214. synth_ai/data/__init__.py +83 -0
  215. synth_ai/data/enums.py +122 -0
  216. synth_ai/data/rewards.py +249 -0
  217. synth_ai/data/traces.py +35 -0
  218. synth_ai/products/__init__.py +6 -0
  219. synth_ai/products/graph_evolve/__init__.py +45 -0
  220. synth_ai/products/graph_evolve/client.py +226 -0
  221. synth_ai/products/graph_evolve/config.py +591 -0
  222. synth_ai/products/graph_evolve/converters/__init__.py +42 -0
  223. synth_ai/products/graph_evolve/converters/openai_sft.py +484 -0
  224. synth_ai/products/graph_evolve/examples/hotpotqa/config.toml +109 -0
  225. synth_ai/products/graph_evolve/run.py +222 -0
  226. synth_ai/products/graph_gepa/__init__.py +23 -0
  227. synth_ai/products/graph_gepa/converters/__init__.py +19 -0
  228. synth_ai/products/graph_gepa/converters/openai_sft.py +29 -0
  229. synth_ai/sdk/__init__.py +129 -0
  230. synth_ai/sdk/api/__init__.py +1 -0
  231. synth_ai/sdk/api/eval/__init__.py +33 -0
  232. synth_ai/sdk/api/eval/job.py +732 -0
  233. synth_ai/sdk/api/models/supported.py +514 -0
  234. synth_ai/sdk/api/research_agent/__init__.py +296 -0
  235. synth_ai/sdk/api/train/__init__.py +85 -0
  236. synth_ai/sdk/api/train/builders.py +1076 -0
  237. synth_ai/sdk/api/train/cli.py +2196 -0
  238. synth_ai/sdk/api/train/config_finder.py +267 -0
  239. synth_ai/sdk/api/train/configs/__init__.py +67 -0
  240. synth_ai/sdk/api/train/configs/prompt_learning.py +1800 -0
  241. synth_ai/sdk/api/train/configs/rl.py +436 -0
  242. synth_ai/sdk/api/train/configs/sft.py +263 -0
  243. synth_ai/sdk/api/train/configs/shared.py +81 -0
  244. synth_ai/sdk/api/train/context_learning.py +312 -0
  245. synth_ai/sdk/api/train/env_resolver.py +418 -0
  246. synth_ai/sdk/api/train/graph_validators.py +216 -0
  247. synth_ai/sdk/api/train/graphgen.py +1102 -0
  248. synth_ai/sdk/api/train/graphgen_models.py +873 -0
  249. synth_ai/sdk/api/train/graphgen_validators.py +109 -0
  250. synth_ai/sdk/api/train/local_api.py +10 -0
  251. synth_ai/sdk/api/train/pollers.py +160 -0
  252. synth_ai/sdk/api/train/progress/__init__.py +97 -0
  253. synth_ai/sdk/api/train/progress/dataclasses.py +569 -0
  254. synth_ai/sdk/api/train/progress/events.py +326 -0
  255. synth_ai/sdk/api/train/progress/results.py +428 -0
  256. synth_ai/sdk/api/train/progress/tracker.py +641 -0
  257. synth_ai/sdk/api/train/prompt_learning.py +800 -0
  258. synth_ai/sdk/api/train/rl.py +478 -0
  259. synth_ai/sdk/api/train/sft.py +398 -0
  260. synth_ai/sdk/api/train/summary.py +522 -0
  261. synth_ai/sdk/api/train/supported_algos.py +147 -0
  262. synth_ai/sdk/api/train/task_app.py +351 -0
  263. synth_ai/sdk/api/train/utils.py +279 -0
  264. synth_ai/sdk/api/train/validators.py +2424 -0
  265. synth_ai/sdk/graphs/__init__.py +15 -0
  266. synth_ai/sdk/graphs/completions.py +776 -0
  267. synth_ai/sdk/graphs/verifier_schemas.py +222 -0
  268. synth_ai/sdk/inference/__init__.py +6 -0
  269. synth_ai/sdk/inference/client.py +128 -0
  270. synth_ai/sdk/jobs/__init__.py +16 -0
  271. synth_ai/sdk/jobs/client.py +371 -0
  272. synth_ai/sdk/learning/__init__.py +99 -0
  273. synth_ai/sdk/learning/client.py +240 -0
  274. synth_ai/sdk/learning/context_learning_client.py +531 -0
  275. synth_ai/sdk/learning/context_learning_types.py +294 -0
  276. synth_ai/sdk/learning/ft_client.py +7 -0
  277. synth_ai/sdk/learning/health.py +49 -0
  278. synth_ai/sdk/learning/jobs.py +202 -0
  279. synth_ai/sdk/learning/prompt_extraction.py +334 -0
  280. synth_ai/sdk/learning/prompt_learning_client.py +455 -0
  281. synth_ai/sdk/learning/prompt_learning_types.py +186 -0
  282. synth_ai/sdk/learning/rl/__init__.py +35 -0
  283. synth_ai/sdk/learning/rl/client.py +268 -0
  284. synth_ai/sdk/learning/rl/contracts.py +23 -0
  285. synth_ai/sdk/learning/rl/env_keys.py +166 -0
  286. synth_ai/sdk/learning/rl/secrets.py +13 -0
  287. synth_ai/sdk/learning/sft/client.py +95 -0
  288. synth_ai/sdk/learning/sft/config.py +270 -0
  289. synth_ai/sdk/learning/sft/data.py +698 -0
  290. synth_ai/sdk/learning/validators.py +52 -0
  291. synth_ai/sdk/localapi/__init__.py +40 -0
  292. synth_ai/sdk/localapi/apps/__init__.py +28 -0
  293. synth_ai/sdk/localapi/client.py +10 -0
  294. synth_ai/sdk/localapi/contracts.py +10 -0
  295. synth_ai/sdk/localapi/helpers.py +519 -0
  296. synth_ai/sdk/localapi/rollouts.py +93 -0
  297. synth_ai/sdk/localapi/server.py +29 -0
  298. synth_ai/sdk/localapi/template.py +49 -0
  299. synth_ai/sdk/streaming/__init__.py +35 -0
  300. synth_ai/sdk/streaming/config.py +94 -0
  301. synth_ai/sdk/streaming/handlers.py +1997 -0
  302. synth_ai/sdk/streaming/streamer.py +708 -0
  303. synth_ai/sdk/streaming/types.py +112 -0
  304. synth_ai/sdk/task/__init__.py +164 -0
  305. synth_ai/sdk/task/apps/__init__.py +169 -0
  306. synth_ai/sdk/task/client.py +175 -0
  307. synth_ai/sdk/task/config.py +256 -0
  308. synth_ai/sdk/task/contracts.py +340 -0
  309. synth_ai/sdk/task/datasets.py +108 -0
  310. synth_ai/sdk/task/in_process.py +1200 -0
  311. synth_ai/sdk/task/in_process_runner.py +314 -0
  312. synth_ai/sdk/task/inference_api.py +299 -0
  313. synth_ai/sdk/task/proxy.py +287 -0
  314. synth_ai/sdk/task/rubrics/__init__.py +54 -0
  315. synth_ai/sdk/task/rubrics/loaders.py +156 -0
  316. synth_ai/sdk/task/rubrics/strict.py +148 -0
  317. synth_ai/sdk/task/rubrics.py +219 -0
  318. synth_ai/sdk/task/server.py +640 -0
  319. synth_ai/sdk/task/trace_correlation_helpers.py +557 -0
  320. synth_ai/sdk/task/tracing_utils.py +95 -0
  321. synth_ai/sdk/task/validators.py +441 -0
  322. synth_ai/sdk/training/__init__.py +93 -0
  323. synth_ai/sdk/tunnels/__init__.py +118 -0
  324. synth_ai/sdk/tunnels/cleanup.py +83 -0
  325. synth_ai/sdk/tunnels/ports.py +120 -0
  326. synth_ai/sdk/tunnels/tunneled_api.py +363 -0
  327. synth_ai/utils/__init__.py +213 -0
  328. synth_ai-0.4.4.dist-info/METADATA +262 -0
  329. synth_ai-0.4.4.dist-info/RECORD +369 -0
  330. synth_ai-0.4.4.dist-info/top_level.txt +1 -0
  331. examples/__init__.py +0 -16
  332. examples/analyze_semantic_words.sh +0 -17
  333. examples/crafter_debug_render.py +0 -186
  334. examples/dev/qwen3_32b_qlora_4xh100.toml +0 -40
  335. examples/multi_step/configs/README_verilog_rl.md +0 -77
  336. examples/multi_step/configs/VERILOG_REWARDS.md +0 -90
  337. examples/multi_step/configs/VERILOG_RL_CHECKLIST.md +0 -183
  338. examples/multi_step/configs/crafter_eval_synth_qwen4b.toml +0 -35
  339. examples/multi_step/configs/crafter_eval_text_only_groq_qwen32b.toml +0 -36
  340. examples/multi_step/configs/crafter_rl_outcome.toml +0 -74
  341. examples/multi_step/configs/crafter_rl_stepwise_hosted_judge.toml +0 -187
  342. examples/multi_step/configs/crafter_rl_stepwise_shaped.toml +0 -83
  343. examples/multi_step/configs/crafter_rl_stepwise_simple.toml +0 -78
  344. examples/multi_step/configs/crafter_synth_backend.md +0 -40
  345. examples/multi_step/configs/verilog_eval_groq_qwen32b.toml +0 -31
  346. examples/multi_step/configs/verilog_eval_synth_qwen8b.toml +0 -33
  347. examples/multi_step/configs/verilog_rl_lora.toml +0 -190
  348. examples/multi_step/crafter_rl_lora.md +0 -70
  349. examples/multi_step/judges/crafter_backend_judge.py +0 -220
  350. examples/multi_step/judges/verilog_backend_judge.py +0 -234
  351. examples/multi_step/readme.md +0 -48
  352. examples/multi_step/sse_metrics_streaming_notes.md +0 -357
  353. examples/multi_step/task_app_config_notes.md +0 -494
  354. examples/multi_step/verilog_rl_lora.md +0 -218
  355. examples/qwen_coder/README.md +0 -102
  356. examples/qwen_coder/_shared.py +0 -113
  357. examples/qwen_coder/configs/coder_lora_30b.toml +0 -61
  358. examples/qwen_coder/configs/coder_lora_4b.toml +0 -57
  359. examples/qwen_coder/configs/coder_lora_small.toml +0 -58
  360. examples/qwen_coder/generate_dataset.py +0 -98
  361. examples/qwen_coder/infer_ft_smoke.py +0 -65
  362. examples/qwen_coder/infer_prod_proxy.py +0 -73
  363. examples/qwen_coder/infer_via_synth.py +0 -87
  364. examples/qwen_coder/scripts/infer_coder.sh +0 -19
  365. examples/qwen_coder/scripts/train_coder_30b.sh +0 -22
  366. examples/qwen_coder/sft_full_17b.py +0 -103
  367. examples/qwen_coder/sft_lora_30b.py +0 -110
  368. examples/qwen_coder/subset_jsonl.py +0 -39
  369. examples/qwen_coder/todos.md +0 -38
  370. examples/qwen_coder/validate_jsonl.py +0 -60
  371. examples/rl/README.md +0 -169
  372. examples/rl/download_dataset.py +0 -80
  373. examples/run_crafter_demo.sh +0 -10
  374. examples/sft/README.md +0 -139
  375. examples/sft/configs/crafter_fft_qwen0p6b.toml +0 -44
  376. examples/sft/configs/crafter_lora_qwen0p6b.toml +0 -45
  377. examples/sft/evaluate.py +0 -119
  378. examples/sft/export_dataset.py +0 -117
  379. examples/sft/generate_traces.py +0 -164
  380. examples/swe/__init__.py +0 -12
  381. examples/swe/task_app/README.md +0 -105
  382. examples/swe/task_app/__init__.py +0 -2
  383. examples/swe/task_app/grpo_swe_mini.py +0 -601
  384. examples/swe/task_app/grpo_swe_mini_task_app.py +0 -136
  385. examples/swe/task_app/hosted/README.md +0 -173
  386. examples/swe/task_app/hosted/__init__.py +0 -5
  387. examples/swe/task_app/hosted/branching.py +0 -143
  388. examples/swe/task_app/hosted/environment_routes.py +0 -1289
  389. examples/swe/task_app/hosted/envs/__init__.py +0 -1
  390. examples/swe/task_app/hosted/envs/crafter/__init__.py +0 -6
  391. examples/swe/task_app/hosted/envs/crafter/app.py +0 -1
  392. examples/swe/task_app/hosted/envs/crafter/environment.py +0 -522
  393. examples/swe/task_app/hosted/envs/crafter/policy.py +0 -478
  394. examples/swe/task_app/hosted/envs/crafter/react_agent.py +0 -108
  395. examples/swe/task_app/hosted/envs/crafter/shared.py +0 -305
  396. examples/swe/task_app/hosted/envs/crafter/tools.py +0 -47
  397. examples/swe/task_app/hosted/envs/mini_swe/__init__.py +0 -8
  398. examples/swe/task_app/hosted/envs/mini_swe/environment.py +0 -1164
  399. examples/swe/task_app/hosted/envs/mini_swe/policy.py +0 -355
  400. examples/swe/task_app/hosted/envs/mini_swe/shared.py +0 -83
  401. examples/swe/task_app/hosted/envs/mini_swe/tools.py +0 -96
  402. examples/swe/task_app/hosted/hosted_app.py +0 -204
  403. examples/swe/task_app/hosted/inference/__init__.py +0 -5
  404. examples/swe/task_app/hosted/inference/openai_client.py +0 -618
  405. examples/swe/task_app/hosted/main.py +0 -100
  406. examples/swe/task_app/hosted/policy_routes.py +0 -1079
  407. examples/swe/task_app/hosted/registry.py +0 -195
  408. examples/swe/task_app/hosted/rollout.py +0 -1911
  409. examples/swe/task_app/hosted/storage/__init__.py +0 -5
  410. examples/swe/task_app/hosted/storage/volume.py +0 -211
  411. examples/swe/task_app/hosted/test_agents.py +0 -161
  412. examples/swe/task_app/hosted/test_service.py +0 -136
  413. examples/swe/task_app/hosted/utils.py +0 -62
  414. examples/task_apps/IMAGE_ONLY_EVAL_QUICKSTART.md +0 -258
  415. examples/task_apps/TESTING.md +0 -275
  416. examples/task_apps/crafter/CREATE_SFT_DATASET.md +0 -273
  417. examples/task_apps/crafter/EVAL_IMAGE_ONLY_RESULTS.md +0 -152
  418. examples/task_apps/crafter/FILTER_COMMAND_STATUS.md +0 -174
  419. examples/task_apps/crafter/FILTER_COMMAND_SUCCESS.md +0 -268
  420. examples/task_apps/crafter/QUERY_EXAMPLES.md +0 -203
  421. examples/task_apps/crafter/README_IMAGE_ONLY_EVAL.md +0 -316
  422. examples/task_apps/crafter/__init__.py +0 -0
  423. examples/task_apps/crafter/eval_image_only_gpt4o.toml +0 -28
  424. examples/task_apps/crafter/eval_text_only_groq_llama.toml +0 -36
  425. examples/task_apps/crafter/filter_sft_dataset.toml +0 -16
  426. examples/task_apps/crafter/task_app/README.md +0 -42
  427. examples/task_apps/crafter/task_app/__init__.py +0 -5
  428. examples/task_apps/crafter/task_app/grpo_crafter.py +0 -973
  429. examples/task_apps/crafter/task_app/grpo_crafter_task_app.py +0 -146
  430. examples/task_apps/crafter/task_app/synth_envs_hosted/README.md +0 -173
  431. examples/task_apps/crafter/task_app/synth_envs_hosted/__init__.py +0 -5
  432. examples/task_apps/crafter/task_app/synth_envs_hosted/branching.py +0 -143
  433. examples/task_apps/crafter/task_app/synth_envs_hosted/environment_routes.py +0 -1226
  434. examples/task_apps/crafter/task_app/synth_envs_hosted/envs/__init__.py +0 -1
  435. examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/__init__.py +0 -6
  436. examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/app.py +0 -1
  437. examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/environment.py +0 -532
  438. examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/policy.py +0 -547
  439. examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/react_agent.py +0 -123
  440. examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/shared.py +0 -305
  441. examples/task_apps/crafter/task_app/synth_envs_hosted/envs/crafter/tools.py +0 -47
  442. examples/task_apps/crafter/task_app/synth_envs_hosted/hosted_app.py +0 -204
  443. examples/task_apps/crafter/task_app/synth_envs_hosted/inference/__init__.py +0 -5
  444. examples/task_apps/crafter/task_app/synth_envs_hosted/inference/openai_client.py +0 -704
  445. examples/task_apps/crafter/task_app/synth_envs_hosted/main.py +0 -100
  446. examples/task_apps/crafter/task_app/synth_envs_hosted/policy_routes.py +0 -1152
  447. examples/task_apps/crafter/task_app/synth_envs_hosted/registry.py +0 -195
  448. examples/task_apps/crafter/task_app/synth_envs_hosted/rollout.py +0 -2160
  449. examples/task_apps/crafter/task_app/synth_envs_hosted/storage/__init__.py +0 -5
  450. examples/task_apps/crafter/task_app/synth_envs_hosted/storage/volume.py +0 -211
  451. examples/task_apps/crafter/task_app/synth_envs_hosted/test_agents.py +0 -161
  452. examples/task_apps/crafter/task_app/synth_envs_hosted/test_service.py +0 -136
  453. examples/task_apps/crafter/task_app/synth_envs_hosted/utils.py +0 -218
  454. examples/task_apps/dev/pokemon_emerald/__init__.py +0 -2
  455. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/README.md +0 -811
  456. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/__init__.py +0 -120
  457. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/action.py +0 -160
  458. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/memory.py +0 -155
  459. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/perception.py +0 -69
  460. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/planning.py +0 -96
  461. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/simple.py +0 -1502
  462. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/agent/system_prompt.py +0 -4
  463. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/grab_map.py +0 -68
  464. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/manual.py +0 -216
  465. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/__init__.py +0 -35
  466. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/emerald_utils.py +0 -631
  467. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/emulator.py +0 -1544
  468. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/enums.py +0 -1428
  469. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/memory_reader.py +0 -4848
  470. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/types.py +0 -41
  471. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pokemon_env/utils.py +0 -298
  472. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/pyproject.toml +0 -95
  473. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/run.py +0 -204
  474. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/server/__init__.py +0 -0
  475. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/server/app.py +0 -2152
  476. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/server/client.py +0 -429
  477. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/server/frame_server.py +0 -155
  478. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/README.md +0 -78
  479. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/__init__.py +0 -0
  480. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/run_tests.py +0 -122
  481. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_agent_direct.py +0 -76
  482. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_agent_prompts.py +0 -413
  483. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_battle_state_formatting.py +0 -204
  484. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_dialogue_detection.py +0 -133
  485. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_dialogue_detection_comprehensive.py +0 -229
  486. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_direct_agent_emulator.py +0 -300
  487. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_fps_adjustment_pytest.py +0 -205
  488. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_house_to_outside_direct.py +0 -200
  489. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_house_to_outside_transition.py +0 -284
  490. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_map_ground_truth_comparison.py +0 -468
  491. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_memory_map.py +0 -575
  492. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_server_map_validation.py +0 -311
  493. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/tests/test_torchic_state.py +0 -259
  494. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/__init__.py +0 -0
  495. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/anticheat.py +0 -372
  496. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/checkpoint.py +0 -296
  497. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/error_handler.py +0 -275
  498. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/get_local_ip.py +0 -22
  499. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/helpers.py +0 -44
  500. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/llm_logger.py +0 -514
  501. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_formatter.py +0 -415
  502. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_stitcher.py +0 -1763
  503. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_stitcher_singleton.py +0 -33
  504. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_trimmer.py +0 -106
  505. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/map_visualizer.py +0 -334
  506. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/ocr_dialogue.py +0 -1020
  507. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/recording.py +0 -188
  508. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/state_formatter.py +0 -1481
  509. examples/task_apps/dev/pokemon_emerald/external/pokeagent-speedrun/utils/vlm.py +0 -862
  510. examples/task_apps/dev/pokemon_emerald/modal_app.py +0 -114
  511. examples/task_apps/dev/pokemon_emerald/task_app/README.md +0 -81
  512. examples/task_apps/dev/pokemon_emerald/task_app/__init__.py +0 -6
  513. examples/task_apps/dev/pokemon_emerald/task_app/pokemon_emerald.py +0 -685
  514. examples/task_apps/enron/__init__.py +0 -1
  515. examples/task_apps/enron/eval_groq_qwen32.toml +0 -16
  516. examples/task_apps/enron/filter_sft.toml +0 -5
  517. examples/task_apps/enron/task_app/README.md +0 -14
  518. examples/task_apps/enron/task_app/__init__.py +0 -1
  519. examples/task_apps/enron/task_app/grpo_enron.py +0 -906
  520. examples/task_apps/enron/task_app/grpo_enron_task_app.py +0 -146
  521. examples/task_apps/enron/tests/__init__.py +0 -4
  522. examples/task_apps/enron/tests/conftest.py +0 -115
  523. examples/task_apps/enron/tests/integration/__init__.py +0 -4
  524. examples/task_apps/enron/tests/integration/test_enron_eval.py +0 -179
  525. examples/task_apps/enron/tests/integration/test_enron_rollout.py +0 -135
  526. examples/task_apps/enron/tests/unit/__init__.py +0 -4
  527. examples/task_apps/enron/tests/unit/test_enron_environment.py +0 -126
  528. examples/task_apps/math/README.md +0 -22
  529. examples/task_apps/math/__init__.py +0 -0
  530. examples/task_apps/math/math_single_step.py +0 -1000
  531. examples/task_apps/math/math_task_app.py +0 -115
  532. examples/task_apps/pokemon_battle/__init__.py +0 -2
  533. examples/task_apps/pokemon_battle/modal_app.py +0 -104
  534. examples/task_apps/pokemon_battle/task_app/README.md +0 -68
  535. examples/task_apps/pokemon_battle/task_app/__init__.py +0 -6
  536. examples/task_apps/pokemon_battle/task_app/pokemon_showdown.py +0 -932
  537. examples/task_apps/pokemon_red/EVAL_IMAGE_ONLY_COMPLETE.md +0 -283
  538. examples/task_apps/pokemon_red/EVAL_IMAGE_ONLY_STATUS.md +0 -155
  539. examples/task_apps/pokemon_red/README.md +0 -357
  540. examples/task_apps/pokemon_red/README_IMAGE_ONLY_EVAL.md +0 -415
  541. examples/task_apps/pokemon_red/__init__.py +0 -3
  542. examples/task_apps/pokemon_red/eval_image_only_gpt4o.toml +0 -29
  543. examples/task_apps/pokemon_red/eval_pokemon_red_policy.py +0 -225
  544. examples/task_apps/pokemon_red/pallet_town_rl_config.toml +0 -75
  545. examples/task_apps/pokemon_red/task_app.py +0 -799
  546. examples/task_apps/pokemon_red/test_pallet_town_rewards.py +0 -193
  547. examples/task_apps/sokoban/README.md +0 -307
  548. examples/task_apps/sokoban/__init__.py +0 -3
  549. examples/task_apps/sokoban/eval_groq_qwen32.toml +0 -16
  550. examples/task_apps/sokoban/eval_openai_gpt5.toml +0 -16
  551. examples/task_apps/sokoban/filter_sft.toml +0 -5
  552. examples/task_apps/sokoban/task_app.py +0 -1058
  553. examples/task_apps/sokoban/tests/__init__.py +0 -4
  554. examples/task_apps/sokoban/tests/conftest.py +0 -113
  555. examples/task_apps/sokoban/tests/integration/__init__.py +0 -4
  556. examples/task_apps/sokoban/tests/integration/test_sokoban_eval.py +0 -57
  557. examples/task_apps/sokoban/tests/integration/test_sokoban_rollout.py +0 -198
  558. examples/task_apps/sokoban/tests/unit/__init__.py +0 -4
  559. examples/task_apps/sokoban/tests/unit/test_sokoban_environment.py +0 -114
  560. examples/task_apps/verilog/__init__.py +0 -1
  561. examples/task_apps/verilog/eval_groq_qwen32b.toml +0 -24
  562. examples/task_apps/verilog/filter_sft.toml +0 -5
  563. examples/task_apps/verilog/task_app/README.md +0 -12
  564. examples/task_apps/verilog/task_app/__init__.py +0 -1
  565. examples/task_apps/verilog/task_app/grpo_verilog.py +0 -1166
  566. examples/task_apps/verilog/task_app/grpo_verilog_task_app.py +0 -145
  567. examples/task_apps/verilog/tests/__init__.py +0 -4
  568. examples/task_apps/verilog/tests/conftest.py +0 -115
  569. examples/task_apps/verilog/tests/integration/__init__.py +0 -4
  570. examples/task_apps/verilog/tests/integration/test_verilog_eval.py +0 -181
  571. examples/task_apps/verilog/tests/integration/test_verilog_rollout.py +0 -55
  572. examples/task_apps/verilog/tests/unit/__init__.py +0 -4
  573. examples/task_apps/verilog/tests/unit/test_verilog_scoring.py +0 -118
  574. examples/vlm/PROPOSAL.md +0 -53
  575. examples/vlm/README.md +0 -68
  576. examples/vlm/configs/crafter_vlm_gpt4o.toml +0 -44
  577. examples/vlm/crafter_image_only_agent.py +0 -207
  578. examples/vlm/crafter_openai_vlm_agent.py +0 -277
  579. examples/vlm/filter_image_rows.py +0 -63
  580. examples/vlm/run_crafter_vlm_benchmark.py +0 -316
  581. examples/warming_up_to_rl/analyze_trace_db.py +0 -422
  582. examples/warming_up_to_rl/configs/crafter_fft.toml +0 -48
  583. examples/warming_up_to_rl/configs/crafter_fft_4b.toml +0 -54
  584. examples/warming_up_to_rl/configs/eval_fft_qwen4b.toml +0 -20
  585. examples/warming_up_to_rl/configs/eval_groq_qwen32b.toml +0 -13
  586. examples/warming_up_to_rl/configs/eval_modal_qwen4b.toml +0 -23
  587. examples/warming_up_to_rl/configs/eval_stepwise_complex.toml +0 -35
  588. examples/warming_up_to_rl/configs/eval_stepwise_consistent.toml +0 -26
  589. examples/warming_up_to_rl/configs/eval_stepwise_per_achievement.toml +0 -36
  590. examples/warming_up_to_rl/configs/eval_stepwise_simple.toml +0 -32
  591. examples/warming_up_to_rl/configs/rl_from_base_qwen4b.toml +0 -83
  592. examples/warming_up_to_rl/configs/rl_from_ft.toml +0 -56
  593. examples/warming_up_to_rl/export_trace_sft.py +0 -723
  594. examples/warming_up_to_rl/groq_test.py +0 -97
  595. examples/warming_up_to_rl/manage_secrets.py +0 -131
  596. examples/warming_up_to_rl/old/event_rewards.md +0 -234
  597. examples/warming_up_to_rl/old/notes.md +0 -73
  598. examples/warming_up_to_rl/readme.md +0 -179
  599. examples/warming_up_to_rl/run_eval.py +0 -736
  600. examples/warming_up_to_rl/run_fft_and_save.py +0 -380
  601. examples/warming_up_to_rl/run_local_rollout.py +0 -239
  602. examples/warming_up_to_rl/run_local_rollout_modal.py +0 -248
  603. examples/warming_up_to_rl/run_local_rollout_parallel.py +0 -405
  604. examples/warming_up_to_rl/run_local_rollout_traced.py +0 -477
  605. examples/warming_up_to_rl/run_rl_and_save.py +0 -124
  606. examples/warming_up_to_rl/run_rollout_remote.py +0 -156
  607. examples/workflows/__init__.py +0 -0
  608. examples/workflows/math_rl/__init__.py +0 -0
  609. examples/workflows/math_rl/configs/eval_base_qwen.toml +0 -15
  610. examples/workflows/math_rl/configs/eval_rl_qwen.toml +0 -11
  611. examples/workflows/math_rl/configs/rl_from_base_qwen.toml +0 -35
  612. examples/workflows/math_rl/configs/rl_from_base_qwen17.toml +0 -74
  613. examples/workflows/math_rl/configs/rl_from_ft_qwen.toml +0 -35
  614. examples/workflows/math_rl/download_dataset.py +0 -80
  615. examples/workflows/math_rl/run_eval.py +0 -436
  616. examples/workflows/math_rl/run_rl_and_save.py +0 -111
  617. synth_ai/api/models/supported.py +0 -377
  618. synth_ai/api/train/__init__.py +0 -5
  619. synth_ai/api/train/builders.py +0 -351
  620. synth_ai/api/train/cli.py +0 -635
  621. synth_ai/api/train/config_finder.py +0 -228
  622. synth_ai/api/train/configs/__init__.py +0 -44
  623. synth_ai/api/train/configs/rl.py +0 -134
  624. synth_ai/api/train/configs/sft.py +0 -95
  625. synth_ai/api/train/configs/shared.py +0 -24
  626. synth_ai/api/train/env_resolver.py +0 -349
  627. synth_ai/api/train/pollers.py +0 -75
  628. synth_ai/api/train/supported_algos.py +0 -147
  629. synth_ai/api/train/task_app.py +0 -195
  630. synth_ai/api/train/utils.py +0 -225
  631. synth_ai/cli/_modal_wrapper.py +0 -29
  632. synth_ai/cli/_storage.py +0 -20
  633. synth_ai/cli/_typer_patch.py +0 -49
  634. synth_ai/cli/_validate_task_app.py +0 -11
  635. synth_ai/cli/balance.py +0 -216
  636. synth_ai/cli/calc.py +0 -84
  637. synth_ai/cli/demo.py +0 -165
  638. synth_ai/cli/legacy_root_backup.py +0 -468
  639. synth_ai/cli/man.py +0 -106
  640. synth_ai/cli/recent.py +0 -132
  641. synth_ai/cli/rl_demo.py +0 -254
  642. synth_ai/cli/status.py +0 -134
  643. synth_ai/cli/task_apps.py +0 -4523
  644. synth_ai/cli/traces.py +0 -164
  645. synth_ai/cli/tui.py +0 -57
  646. synth_ai/cli/watch.py +0 -506
  647. synth_ai/compound/cais.py +0 -0
  648. synth_ai/config/base_url.py +0 -107
  649. synth_ai/core/experiment.py +0 -13
  650. synth_ai/core/system.py +0 -15
  651. synth_ai/demo_registry.py +0 -295
  652. synth_ai/demos/core/__init__.py +0 -1
  653. synth_ai/demos/core/cli.py +0 -1718
  654. synth_ai/demos/demo_task_apps/core.py +0 -440
  655. synth_ai/demos/demo_task_apps/crafter/grpo_crafter_task_app.py +0 -184
  656. synth_ai/demos/demo_task_apps/math/config.toml +0 -74
  657. synth_ai/demos/demo_task_apps/math/deploy_task_app.sh +0 -22
  658. synth_ai/demos/demo_task_apps/math/modal_task_app.py +0 -739
  659. synth_ai/demos/demo_task_apps/math/task_app_entry.py +0 -37
  660. synth_ai/environments/__init__.py +0 -31
  661. synth_ai/environments/environment/__init__.py +0 -1
  662. synth_ai/environments/environment/artifacts/__init__.py +0 -1
  663. synth_ai/environments/environment/artifacts/base.py +0 -52
  664. synth_ai/environments/environment/core.py +0 -67
  665. synth_ai/environments/environment/db/__init__.py +0 -1
  666. synth_ai/environments/environment/db/sqlite.py +0 -45
  667. synth_ai/environments/environment/registry.py +0 -233
  668. synth_ai/environments/environment/resources/sqlite.py +0 -45
  669. synth_ai/environments/environment/results.py +0 -1
  670. synth_ai/environments/environment/rewards/__init__.py +0 -1
  671. synth_ai/environments/environment/rewards/core.py +0 -29
  672. synth_ai/environments/environment/shared_engine.py +0 -26
  673. synth_ai/environments/environment/tools/__init__.py +0 -200
  674. synth_ai/environments/examples/__init__.py +0 -1
  675. synth_ai/environments/examples/bandit/__init__.py +0 -33
  676. synth_ai/environments/examples/bandit/engine.py +0 -302
  677. synth_ai/environments/examples/bandit/environment.py +0 -194
  678. synth_ai/environments/examples/bandit/taskset.py +0 -200
  679. synth_ai/environments/examples/crafter_classic/__init__.py +0 -8
  680. synth_ai/environments/examples/crafter_classic/agent_demos/analyze_semantic_words_markdown.py +0 -250
  681. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_comprehensive_evaluation.py +0 -59
  682. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_browser.py +0 -152
  683. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_config.toml +0 -24
  684. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_evaluation_framework.py +0 -1194
  685. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/crafter_synth_config.toml +0 -56
  686. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/filter_config_modal.toml +0 -32
  687. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/filter_traces_sft_turso.py +0 -738
  688. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/kick_off_ft_modal.py +0 -384
  689. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_action_results.py +0 -53
  690. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_agent_actions.py +0 -178
  691. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_latest_run.py +0 -222
  692. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_lm_traces.py +0 -183
  693. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_no_rewards.py +0 -210
  694. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/analyze_trace_issue.py +0 -206
  695. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/check_db_schema.py +0 -49
  696. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/check_latest_results.py +0 -64
  697. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/debug_agent_responses.py +0 -88
  698. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_modal_ft/old/quick_trace_check.py +0 -77
  699. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/compare_experiments.py +0 -324
  700. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/filter_traces_sft_turso.py +0 -580
  701. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/kick_off_ft_oai.py +0 -362
  702. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/multi_model_config.toml +0 -49
  703. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/analyze_enhanced_hooks.py +0 -332
  704. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/analyze_hook_events.py +0 -97
  705. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/analyze_hook_results.py +0 -217
  706. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/check_hook_storage.py +0 -87
  707. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/check_seeds.py +0 -88
  708. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/compare_seed_performance.py +0 -195
  709. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/custom_eval_pipelines.py +0 -400
  710. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/plot_hook_frequency.py +0 -195
  711. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/old/seed_analysis_summary.py +0 -56
  712. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_openai_ft/run_rollouts_for_models_and_compare_v3.py +0 -858
  713. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_quick_evaluation.py +0 -52
  714. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_react_agent.py +0 -874
  715. synth_ai/environments/examples/crafter_classic/agent_demos/crafter_trace_evaluation.py +0 -1412
  716. synth_ai/environments/examples/crafter_classic/agent_demos/example_v3_usage.py +0 -216
  717. synth_ai/environments/examples/crafter_classic/agent_demos/old/compare_traces.py +0 -296
  718. synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_comprehensive_evaluation.py +0 -58
  719. synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_env_serialization.py +0 -464
  720. synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_evaluation_browser.py +0 -152
  721. synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_quick_evaluation.py +0 -51
  722. synth_ai/environments/examples/crafter_classic/agent_demos/old/crafter_trace_evaluation.py +0 -1412
  723. synth_ai/environments/examples/crafter_classic/agent_demos/old/debug_player_loss.py +0 -112
  724. synth_ai/environments/examples/crafter_classic/agent_demos/old/diagnose_service.py +0 -203
  725. synth_ai/environments/examples/crafter_classic/agent_demos/old/diagnose_slowness.py +0 -305
  726. synth_ai/environments/examples/crafter_classic/agent_demos/old/eval_by_difficulty.py +0 -126
  727. synth_ai/environments/examples/crafter_classic/agent_demos/old/eval_example.py +0 -94
  728. synth_ai/environments/examples/crafter_classic/agent_demos/old/explore_saved_states.py +0 -142
  729. synth_ai/environments/examples/crafter_classic/agent_demos/old/filter_traces_sft.py +0 -26
  730. synth_ai/environments/examples/crafter_classic/agent_demos/old/filter_traces_sft_OLD.py +0 -984
  731. synth_ai/environments/examples/crafter_classic/agent_demos/old/generate_ft_data_gemini.py +0 -724
  732. synth_ai/environments/examples/crafter_classic/agent_demos/old/generate_ft_data_modal.py +0 -386
  733. synth_ai/environments/examples/crafter_classic/agent_demos/old/generate_ft_metadata.py +0 -205
  734. synth_ai/environments/examples/crafter_classic/agent_demos/old/kick_off_ft_gemini.py +0 -150
  735. synth_ai/environments/examples/crafter_classic/agent_demos/old/kick_off_ft_modal.py +0 -283
  736. synth_ai/environments/examples/crafter_classic/agent_demos/old/prepare_vertex_ft.py +0 -280
  737. synth_ai/environments/examples/crafter_classic/agent_demos/old/profile_env_slowness.py +0 -456
  738. synth_ai/environments/examples/crafter_classic/agent_demos/old/replicate_issue.py +0 -166
  739. synth_ai/environments/examples/crafter_classic/agent_demos/old/run_and_eval.py +0 -102
  740. synth_ai/environments/examples/crafter_classic/agent_demos/old/run_comparison.py +0 -128
  741. synth_ai/environments/examples/crafter_classic/agent_demos/old/run_qwen_rollouts.py +0 -655
  742. synth_ai/environments/examples/crafter_classic/agent_demos/old/trace_eval_OLD.py +0 -202
  743. synth_ai/environments/examples/crafter_classic/agent_demos/old/validate_openai_format.py +0 -166
  744. synth_ai/environments/examples/crafter_classic/config_logging.py +0 -111
  745. synth_ai/environments/examples/crafter_classic/debug_translation.py +0 -0
  746. synth_ai/environments/examples/crafter_classic/engine.py +0 -579
  747. synth_ai/environments/examples/crafter_classic/engine_deterministic_patch.py +0 -64
  748. synth_ai/environments/examples/crafter_classic/engine_helpers/action_map.py +0 -6
  749. synth_ai/environments/examples/crafter_classic/engine_helpers/serialization.py +0 -75
  750. synth_ai/environments/examples/crafter_classic/engine_serialization_patch_v3.py +0 -267
  751. synth_ai/environments/examples/crafter_classic/environment.py +0 -495
  752. synth_ai/environments/examples/crafter_classic/taskset.py +0 -233
  753. synth_ai/environments/examples/crafter_classic/trace_hooks_v3.py +0 -228
  754. synth_ai/environments/examples/crafter_classic/world_config_patch_simple.py +0 -299
  755. synth_ai/environments/examples/crafter_custom/__init__.py +0 -4
  756. synth_ai/environments/examples/crafter_custom/agent_demos/__init__.py +0 -1
  757. synth_ai/environments/examples/crafter_custom/agent_demos/trace_eval.py +0 -202
  758. synth_ai/environments/examples/crafter_custom/crafter/__init__.py +0 -7
  759. synth_ai/environments/examples/crafter_custom/crafter/config.py +0 -182
  760. synth_ai/environments/examples/crafter_custom/crafter/constants.py +0 -8
  761. synth_ai/environments/examples/crafter_custom/crafter/engine.py +0 -269
  762. synth_ai/environments/examples/crafter_custom/crafter/env.py +0 -262
  763. synth_ai/environments/examples/crafter_custom/crafter/objects.py +0 -417
  764. synth_ai/environments/examples/crafter_custom/crafter/recorder.py +0 -187
  765. synth_ai/environments/examples/crafter_custom/crafter/worldgen.py +0 -118
  766. synth_ai/environments/examples/crafter_custom/dataset_builder.py +0 -373
  767. synth_ai/environments/examples/crafter_custom/environment.py +0 -312
  768. synth_ai/environments/examples/crafter_custom/old/analyze_diamond_issue.py +0 -159
  769. synth_ai/environments/examples/crafter_custom/old/analyze_diamond_spawning.py +0 -158
  770. synth_ai/environments/examples/crafter_custom/old/compare_worlds.py +0 -71
  771. synth_ai/environments/examples/crafter_custom/old/dataset_stats.py +0 -105
  772. synth_ai/environments/examples/crafter_custom/old/diamond_spawning_summary.py +0 -119
  773. synth_ai/environments/examples/crafter_custom/old/example_dataset_usage.py +0 -52
  774. synth_ai/environments/examples/crafter_custom/run_dataset.py +0 -305
  775. synth_ai/environments/examples/enron/art_helpers/email_search_tools.py +0 -156
  776. synth_ai/environments/examples/enron/art_helpers/local_email_db.py +0 -281
  777. synth_ai/environments/examples/enron/art_helpers/types_enron.py +0 -25
  778. synth_ai/environments/examples/enron/engine.py +0 -300
  779. synth_ai/environments/examples/enron/environment.py +0 -234
  780. synth_ai/environments/examples/enron/taskset.py +0 -112
  781. synth_ai/environments/examples/enron/units/keyword_stats.py +0 -112
  782. synth_ai/environments/examples/minigrid/__init__.py +0 -48
  783. synth_ai/environments/examples/minigrid/agent_demos/minigrid_evaluation_framework.py +0 -1188
  784. synth_ai/environments/examples/minigrid/agent_demos/minigrid_quick_evaluation.py +0 -48
  785. synth_ai/environments/examples/minigrid/agent_demos/minigrid_react_agent.py +0 -562
  786. synth_ai/environments/examples/minigrid/agent_demos/minigrid_trace_evaluation.py +0 -221
  787. synth_ai/environments/examples/minigrid/engine.py +0 -589
  788. synth_ai/environments/examples/minigrid/environment.py +0 -274
  789. synth_ai/environments/examples/minigrid/environment_mapping.py +0 -242
  790. synth_ai/environments/examples/minigrid/puzzle_loader.py +0 -417
  791. synth_ai/environments/examples/minigrid/taskset.py +0 -583
  792. synth_ai/environments/examples/nethack/__init__.py +0 -7
  793. synth_ai/environments/examples/nethack/achievements.py +0 -337
  794. synth_ai/environments/examples/nethack/agent_demos/nethack_evaluation_framework.py +0 -981
  795. synth_ai/environments/examples/nethack/agent_demos/nethack_quick_evaluation.py +0 -74
  796. synth_ai/environments/examples/nethack/agent_demos/nethack_react_agent.py +0 -831
  797. synth_ai/environments/examples/nethack/engine.py +0 -739
  798. synth_ai/environments/examples/nethack/environment.py +0 -256
  799. synth_ai/environments/examples/nethack/helpers/__init__.py +0 -41
  800. synth_ai/environments/examples/nethack/helpers/action_mapping.py +0 -301
  801. synth_ai/environments/examples/nethack/helpers/nle_wrapper.py +0 -402
  802. synth_ai/environments/examples/nethack/helpers/observation_utils.py +0 -433
  803. synth_ai/environments/examples/nethack/helpers/recording_wrapper.py +0 -200
  804. synth_ai/environments/examples/nethack/helpers/trajectory_recorder.py +0 -269
  805. synth_ai/environments/examples/nethack/helpers/visualization/replay_viewer.py +0 -308
  806. synth_ai/environments/examples/nethack/helpers/visualization/visualizer.py +0 -431
  807. synth_ai/environments/examples/nethack/taskset.py +0 -323
  808. synth_ai/environments/examples/red/__init__.py +0 -7
  809. synth_ai/environments/examples/red/agent_demos/__init__.py +0 -1
  810. synth_ai/environments/examples/red/config_logging.py +0 -110
  811. synth_ai/environments/examples/red/engine.py +0 -721
  812. synth_ai/environments/examples/red/engine_helpers/__init__.py +0 -1
  813. synth_ai/environments/examples/red/engine_helpers/memory_map.py +0 -35
  814. synth_ai/environments/examples/red/engine_helpers/reward_components.py +0 -276
  815. synth_ai/environments/examples/red/engine_helpers/reward_library/__init__.py +0 -142
  816. synth_ai/environments/examples/red/engine_helpers/reward_library/adaptive_rewards.py +0 -57
  817. synth_ai/environments/examples/red/engine_helpers/reward_library/battle_rewards.py +0 -284
  818. synth_ai/environments/examples/red/engine_helpers/reward_library/composite_rewards.py +0 -150
  819. synth_ai/environments/examples/red/engine_helpers/reward_library/economy_rewards.py +0 -138
  820. synth_ai/environments/examples/red/engine_helpers/reward_library/efficiency_rewards.py +0 -57
  821. synth_ai/environments/examples/red/engine_helpers/reward_library/exploration_rewards.py +0 -331
  822. synth_ai/environments/examples/red/engine_helpers/reward_library/novelty_rewards.py +0 -121
  823. synth_ai/environments/examples/red/engine_helpers/reward_library/pallet_town_progression.py +0 -477
  824. synth_ai/environments/examples/red/engine_helpers/reward_library/pallet_town_rewards.py +0 -559
  825. synth_ai/environments/examples/red/engine_helpers/reward_library/pokemon_rewards.py +0 -313
  826. synth_ai/environments/examples/red/engine_helpers/reward_library/social_rewards.py +0 -148
  827. synth_ai/environments/examples/red/engine_helpers/reward_library/story_rewards.py +0 -247
  828. synth_ai/environments/examples/red/engine_helpers/screen_analysis.py +0 -368
  829. synth_ai/environments/examples/red/engine_helpers/state_extraction.py +0 -172
  830. synth_ai/environments/examples/red/environment.py +0 -298
  831. synth_ai/environments/examples/red/taskset.py +0 -79
  832. synth_ai/environments/examples/red/units/__init__.py +0 -1
  833. synth_ai/environments/examples/sokoban/__init__.py +0 -1
  834. synth_ai/environments/examples/sokoban/agent_demos/sokoban_full_eval.py +0 -899
  835. synth_ai/environments/examples/sokoban/engine.py +0 -678
  836. synth_ai/environments/examples/sokoban/engine_helpers/__init__.py +0 -1
  837. synth_ai/environments/examples/sokoban/engine_helpers/room_utils.py +0 -657
  838. synth_ai/environments/examples/sokoban/engine_helpers/vendored/__init__.py +0 -18
  839. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/__init__.py +0 -3
  840. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/boxoban_env.py +0 -131
  841. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/render_utils.py +0 -370
  842. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/room_utils.py +0 -332
  843. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env.py +0 -306
  844. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_fixed_targets.py +0 -67
  845. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_pull.py +0 -115
  846. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_two_player.py +0 -123
  847. synth_ai/environments/examples/sokoban/engine_helpers/vendored/envs/sokoban_env_variations.py +0 -394
  848. synth_ai/environments/examples/sokoban/environment.py +0 -229
  849. synth_ai/environments/examples/sokoban/generate_verified_puzzles.py +0 -440
  850. synth_ai/environments/examples/sokoban/puzzle_loader.py +0 -312
  851. synth_ai/environments/examples/sokoban/taskset.py +0 -544
  852. synth_ai/environments/examples/tictactoe/__init__.py +0 -1
  853. synth_ai/environments/examples/tictactoe/engine.py +0 -368
  854. synth_ai/environments/examples/tictactoe/environment.py +0 -240
  855. synth_ai/environments/examples/tictactoe/taskset.py +0 -215
  856. synth_ai/environments/examples/verilog/__init__.py +0 -10
  857. synth_ai/environments/examples/verilog/engine.py +0 -421
  858. synth_ai/environments/examples/verilog/environment.py +0 -350
  859. synth_ai/environments/examples/verilog/taskset.py +0 -420
  860. synth_ai/environments/examples/wordle/__init__.py +0 -29
  861. synth_ai/environments/examples/wordle/engine.py +0 -398
  862. synth_ai/environments/examples/wordle/environment.py +0 -159
  863. synth_ai/environments/examples/wordle/helpers/generate_instances_wordfreq.py +0 -75
  864. synth_ai/environments/examples/wordle/taskset.py +0 -230
  865. synth_ai/environments/reproducibility/core.py +0 -42
  866. synth_ai/environments/reproducibility/helpers.py +0 -0
  867. synth_ai/environments/reproducibility/tree.py +0 -363
  868. synth_ai/environments/service/app.py +0 -97
  869. synth_ai/environments/service/core_routes.py +0 -1021
  870. synth_ai/environments/service/external_registry.py +0 -56
  871. synth_ai/environments/service/registry.py +0 -9
  872. synth_ai/environments/stateful/__init__.py +0 -1
  873. synth_ai/environments/stateful/core.py +0 -163
  874. synth_ai/environments/stateful/engine.py +0 -21
  875. synth_ai/environments/stateful/state.py +0 -7
  876. synth_ai/environments/tasks/api.py +0 -19
  877. synth_ai/environments/tasks/core.py +0 -81
  878. synth_ai/environments/tasks/filters.py +0 -40
  879. synth_ai/environments/tasks/utils.py +0 -90
  880. synth_ai/environments/v0_observability/history.py +0 -3
  881. synth_ai/environments/v0_observability/log.py +0 -2
  882. synth_ai/evals/__init__.py +0 -15
  883. synth_ai/evals/base.py +0 -13
  884. synth_ai/evals/client.py +0 -82
  885. synth_ai/evals/types.py +0 -42
  886. synth_ai/handshake.py +0 -109
  887. synth_ai/http.py +0 -26
  888. synth_ai/http_client.py +0 -136
  889. synth_ai/inference/__init__.py +0 -5
  890. synth_ai/inference/client.py +0 -34
  891. synth_ai/jobs/client.py +0 -295
  892. synth_ai/judge_schemas.py +0 -127
  893. synth_ai/learning/__init__.py +0 -59
  894. synth_ai/learning/client.py +0 -241
  895. synth_ai/learning/ft_client.py +0 -7
  896. synth_ai/learning/health.py +0 -49
  897. synth_ai/learning/jobs.py +0 -201
  898. synth_ai/learning/rl/__init__.py +0 -39
  899. synth_ai/learning/rl/client.py +0 -267
  900. synth_ai/learning/rl/contracts.py +0 -27
  901. synth_ai/learning/rl/env_keys.py +0 -166
  902. synth_ai/learning/rl/secrets.py +0 -13
  903. synth_ai/learning/sft/client.py +0 -68
  904. synth_ai/learning/sft/config.py +0 -270
  905. synth_ai/learning/sft/data.py +0 -295
  906. synth_ai/learning/validators.py +0 -49
  907. synth_ai/lm/__init__.py +0 -25
  908. synth_ai/task/__init__.py +0 -121
  909. synth_ai/task/apps/__init__.py +0 -129
  910. synth_ai/task/client.py +0 -167
  911. synth_ai/task/config.py +0 -257
  912. synth_ai/task/contracts.py +0 -236
  913. synth_ai/task/datasets.py +0 -108
  914. synth_ai/task/proxy.py +0 -251
  915. synth_ai/task/rubrics/__init__.py +0 -56
  916. synth_ai/task/rubrics/loaders.py +0 -152
  917. synth_ai/task/rubrics/strict.py +0 -149
  918. synth_ai/task/server.py +0 -432
  919. synth_ai/task/trace_correlation_helpers.py +0 -315
  920. synth_ai/task/tracing_utils.py +0 -84
  921. synth_ai/task/validators.py +0 -418
  922. synth_ai/tracing_v3/__init__.py +0 -97
  923. synth_ai/tracing_v3/abstractions.py +0 -302
  924. synth_ai/tracing_v3/config.py +0 -84
  925. synth_ai/tracing_v3/db_config.py +0 -194
  926. synth_ai/tracing_v3/decorators.py +0 -398
  927. synth_ai/tracing_v3/llm_call_record_helpers.py +0 -391
  928. synth_ai/tracing_v3/migration_helper.py +0 -120
  929. synth_ai/tracing_v3/session_tracer.py +0 -540
  930. synth_ai/tracing_v3/storage/base.py +0 -210
  931. synth_ai/tracing_v3/storage/config.py +0 -75
  932. synth_ai/tracing_v3/storage/factory.py +0 -39
  933. synth_ai/tracing_v3/trace_utils.py +0 -317
  934. synth_ai/tracing_v3/turso/daemon.py +0 -151
  935. synth_ai/tracing_v3/turso/models.py +0 -469
  936. synth_ai/tracing_v3/turso/native_manager.py +0 -1209
  937. synth_ai/tracing_v3/utils.py +0 -108
  938. synth_ai/tui/__init__.py +0 -5
  939. synth_ai/tui/__main__.py +0 -13
  940. synth_ai/tui/cli/__init__.py +0 -1
  941. synth_ai/tui/cli/query_experiments.py +0 -164
  942. synth_ai/tui/cli/query_experiments_v3.py +0 -164
  943. synth_ai/tui/dashboard.py +0 -906
  944. synth_ai/v0/api/__init__.py +0 -8
  945. synth_ai/v0/api/models/__init__.py +0 -8
  946. synth_ai/v0/api/models/supported.py +0 -8
  947. synth_ai/v0/config/__init__.py +0 -15
  948. synth_ai/v0/config/base_url.py +0 -12
  949. synth_ai/v0/lm/__init__.py +0 -51
  950. synth_ai/v0/lm/caching/__init__.py +0 -0
  951. synth_ai/v0/lm/caching/constants.py +0 -6
  952. synth_ai/v0/lm/caching/dbs.py +0 -0
  953. synth_ai/v0/lm/caching/ephemeral.py +0 -100
  954. synth_ai/v0/lm/caching/handler.py +0 -137
  955. synth_ai/v0/lm/caching/initialize.py +0 -11
  956. synth_ai/v0/lm/caching/persistent.py +0 -114
  957. synth_ai/v0/lm/config.py +0 -115
  958. synth_ai/v0/lm/constants.py +0 -32
  959. synth_ai/v0/lm/core/__init__.py +0 -8
  960. synth_ai/v0/lm/core/all.py +0 -73
  961. synth_ai/v0/lm/core/exceptions.py +0 -5
  962. synth_ai/v0/lm/core/main.py +0 -331
  963. synth_ai/v0/lm/core/main_v3.py +0 -594
  964. synth_ai/v0/lm/core/synth_models.py +0 -35
  965. synth_ai/v0/lm/core/vendor_clients.py +0 -190
  966. synth_ai/v0/lm/cost/__init__.py +0 -0
  967. synth_ai/v0/lm/cost/monitor.py +0 -1
  968. synth_ai/v0/lm/cost/statefulness.py +0 -1
  969. synth_ai/v0/lm/injection.py +0 -80
  970. synth_ai/v0/lm/overrides.py +0 -206
  971. synth_ai/v0/lm/provider_support/__init__.py +0 -8
  972. synth_ai/v0/lm/provider_support/anthropic.py +0 -972
  973. synth_ai/v0/lm/provider_support/openai.py +0 -1139
  974. synth_ai/v0/lm/provider_support/suppress_logging.py +0 -31
  975. synth_ai/v0/lm/structured_outputs/__init__.py +0 -0
  976. synth_ai/v0/lm/structured_outputs/handler.py +0 -440
  977. synth_ai/v0/lm/structured_outputs/inject.py +0 -297
  978. synth_ai/v0/lm/structured_outputs/rehabilitate.py +0 -185
  979. synth_ai/v0/lm/tools/__init__.py +0 -3
  980. synth_ai/v0/lm/tools/base.py +0 -172
  981. synth_ai/v0/lm/unified_interface.py +0 -202
  982. synth_ai/v0/lm/vendors/__init__.py +0 -0
  983. synth_ai/v0/lm/vendors/base.py +0 -81
  984. synth_ai/v0/lm/vendors/core/__init__.py +0 -0
  985. synth_ai/v0/lm/vendors/core/anthropic_api.py +0 -387
  986. synth_ai/v0/lm/vendors/core/gemini_api.py +0 -292
  987. synth_ai/v0/lm/vendors/core/mistral_api.py +0 -322
  988. synth_ai/v0/lm/vendors/core/openai_api.py +0 -227
  989. synth_ai/v0/lm/vendors/core/synth_dev_api.py +0 -0
  990. synth_ai/v0/lm/vendors/local/__init__.py +0 -0
  991. synth_ai/v0/lm/vendors/local/ollama.py +0 -0
  992. synth_ai/v0/lm/vendors/openai_standard.py +0 -782
  993. synth_ai/v0/lm/vendors/openai_standard_responses.py +0 -259
  994. synth_ai/v0/lm/vendors/retries.py +0 -22
  995. synth_ai/v0/lm/vendors/supported/__init__.py +0 -0
  996. synth_ai/v0/lm/vendors/supported/custom_endpoint.py +0 -415
  997. synth_ai/v0/lm/vendors/supported/deepseek.py +0 -69
  998. synth_ai/v0/lm/vendors/supported/grok.py +0 -75
  999. synth_ai/v0/lm/vendors/supported/groq.py +0 -16
  1000. synth_ai/v0/lm/vendors/supported/ollama.py +0 -15
  1001. synth_ai/v0/lm/vendors/supported/openrouter.py +0 -74
  1002. synth_ai/v0/lm/vendors/supported/together.py +0 -11
  1003. synth_ai/v0/lm/vendors/synth_client.py +0 -835
  1004. synth_ai/v0/lm/warmup.py +0 -186
  1005. synth_ai/v0/tracing/__init__.py +0 -0
  1006. synth_ai/v0/tracing/abstractions.py +0 -224
  1007. synth_ai/v0/tracing/base_client.py +0 -91
  1008. synth_ai/v0/tracing/client_manager.py +0 -131
  1009. synth_ai/v0/tracing/config.py +0 -142
  1010. synth_ai/v0/tracing/context.py +0 -146
  1011. synth_ai/v0/tracing/decorators.py +0 -682
  1012. synth_ai/v0/tracing/events/__init__.py +0 -0
  1013. synth_ai/v0/tracing/events/manage.py +0 -147
  1014. synth_ai/v0/tracing/events/scope.py +0 -86
  1015. synth_ai/v0/tracing/events/store.py +0 -228
  1016. synth_ai/v0/tracing/immediate_client.py +0 -151
  1017. synth_ai/v0/tracing/local.py +0 -18
  1018. synth_ai/v0/tracing/log_client_base.py +0 -73
  1019. synth_ai/v0/tracing/retry_queue.py +0 -186
  1020. synth_ai/v0/tracing/trackers.py +0 -515
  1021. synth_ai/v0/tracing/upload.py +0 -409
  1022. synth_ai/v0/tracing/utils.py +0 -9
  1023. synth_ai/v0/tracing_v1/__init__.py +0 -16
  1024. synth_ai/v0/tracing_v1/abstractions.py +0 -224
  1025. synth_ai/v0/tracing_v1/base_client.py +0 -91
  1026. synth_ai/v0/tracing_v1/client_manager.py +0 -131
  1027. synth_ai/v0/tracing_v1/config.py +0 -142
  1028. synth_ai/v0/tracing_v1/context.py +0 -146
  1029. synth_ai/v0/tracing_v1/decorators.py +0 -703
  1030. synth_ai/v0/tracing_v1/events/__init__.py +0 -0
  1031. synth_ai/v0/tracing_v1/events/manage.py +0 -147
  1032. synth_ai/v0/tracing_v1/events/scope.py +0 -86
  1033. synth_ai/v0/tracing_v1/events/store.py +0 -228
  1034. synth_ai/v0/tracing_v1/immediate_client.py +0 -151
  1035. synth_ai/v0/tracing_v1/local.py +0 -18
  1036. synth_ai/v0/tracing_v1/log_client_base.py +0 -73
  1037. synth_ai/v0/tracing_v1/retry_queue.py +0 -186
  1038. synth_ai/v0/tracing_v1/trackers.py +0 -515
  1039. synth_ai/v0/tracing_v1/upload.py +0 -527
  1040. synth_ai/v0/tracing_v1/utils.py +0 -9
  1041. synth_ai/v0/tracing_v3/__init__.py +0 -10
  1042. synth_ai/v0/tracing_v3/abstractions.py +0 -3
  1043. synth_ai/v0/tracing_v3/decorators.py +0 -3
  1044. synth_ai/v0/tracing_v3/llm_call_record_helpers.py +0 -3
  1045. synth_ai/v0/tracing_v3/session_tracer.py +0 -3
  1046. synth_ai-0.2.14.dist-info/METADATA +0 -139
  1047. synth_ai-0.2.14.dist-info/RECORD +0 -762
  1048. synth_ai-0.2.14.dist-info/top_level.txt +0 -2
  1049. /synth_ai/{demos/demo_task_apps → cli/demo_apps}/crafter/__init__.py +0 -0
  1050. /synth_ai/{demos → cli/demo_apps}/demo_task_apps/__init__.py +0 -0
  1051. /synth_ai/{demos → cli/demo_apps}/demo_task_apps/crafter/configs/crafter_fft_4b.toml +0 -0
  1052. /synth_ai/{demos → cli/demo_apps}/demo_task_apps/crafter/configs/rl_from_base_qwen4b.toml +0 -0
  1053. /synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/__init__.py +0 -0
  1054. /synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/_common.py +0 -0
  1055. /synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/app.py +0 -0
  1056. /synth_ai/{demos → cli/demo_apps}/demo_task_apps/math/deploy_modal.py +0 -0
  1057. {examples/task_apps → synth_ai/core/apps}/__init__.py +0 -0
  1058. /synth_ai/{tracing_v3 → core/tracing_v3}/examples/basic_usage.py +0 -0
  1059. /synth_ai/{tracing_v3 → core/tracing_v3}/hooks.py +0 -0
  1060. /synth_ai/{tracing_v3 → core/tracing_v3}/lm_call_record_abstractions.py +0 -0
  1061. /synth_ai/{tracing_v3 → core/tracing_v3}/replica_sync.py +0 -0
  1062. /synth_ai/{tracing_v3 → core/tracing_v3}/serialization.py +0 -0
  1063. /synth_ai/{tracing_v3 → core/tracing_v3}/storage/__init__.py +0 -0
  1064. /synth_ai/{tracing_v3 → core/tracing_v3}/storage/exceptions.py +0 -0
  1065. /synth_ai/{tracing_v3 → core/tracing_v3}/storage/types.py +0 -0
  1066. /synth_ai/{tracing_v3 → core/tracing_v3}/storage/utils.py +0 -0
  1067. /synth_ai/{tracing_v3 → core/tracing_v3}/turso/__init__.py +0 -0
  1068. /synth_ai/{learning → sdk/learning}/algorithms.py +0 -0
  1069. /synth_ai/{learning → sdk/learning}/config.py +0 -0
  1070. /synth_ai/{learning → sdk/learning}/constants.py +0 -0
  1071. /synth_ai/{learning → sdk/learning}/core.py +0 -0
  1072. /synth_ai/{learning → sdk/learning}/gateway.py +0 -0
  1073. /synth_ai/{learning → sdk/learning}/rl/config.py +0 -0
  1074. /synth_ai/{learning → sdk/learning}/rl_client.py +0 -0
  1075. /synth_ai/{learning → sdk/learning}/sft/__init__.py +0 -0
  1076. /synth_ai/{learning → sdk/learning}/sse.py +0 -0
  1077. /synth_ai/{task → sdk/task}/auth.py +0 -0
  1078. /synth_ai/{task → sdk/task}/errors.py +0 -0
  1079. /synth_ai/{task → sdk/task}/health.py +0 -0
  1080. /synth_ai/{task → sdk/task}/json.py +0 -0
  1081. /synth_ai/{task → sdk/task}/rubrics/models.py +0 -0
  1082. /synth_ai/{task → sdk/task}/rubrics/scoring.py +0 -0
  1083. /synth_ai/{task → sdk/task}/vendors.py +0 -0
  1084. {synth_ai-0.2.14.dist-info → synth_ai-0.4.4.dist-info}/WHEEL +0 -0
  1085. {synth_ai-0.2.14.dist-info → synth_ai-0.4.4.dist-info}/entry_points.txt +0 -0
  1086. {synth_ai-0.2.14.dist-info → synth_ai-0.4.4.dist-info}/licenses/LICENSE +0 -0
@@ -1,1020 +0,0 @@
1
- """
2
- OCR-based dialogue detection for Pokemon Emerald.
3
- Provides fallback text detection when memory reading fails or returns stale data.
4
- """
5
-
6
- import cv2
7
- import numpy as np
8
- from PIL import Image
9
- from typing import Optional, List, Tuple
10
- import re
11
- import logging
12
-
13
- try:
14
- import pytesseract
15
- OCR_AVAILABLE = True
16
- except ImportError:
17
- OCR_AVAILABLE = False
18
- logging.warning("pytesseract not available - OCR dialogue detection disabled")
19
-
20
- logger = logging.getLogger(__name__)
21
-
22
- class OCRDialogueDetector:
23
- """OCR-based dialogue detection for Pokemon Emerald"""
24
-
25
- # Pokemon Emerald dialogue box coordinates (corrected for actual dialogue position)
26
- DIALOGUE_BOX_COORDS = {
27
- 'x': 0, # Full width - dialogue spans entire bottom
28
- 'y': 104, # Dialogue starts around row 104 (from debug analysis)
29
- 'width': 240, # Full screen width
30
- 'height': 56 # Bottom portion height (160-104=56)
31
- }
32
-
33
- # Tighter OCR coordinates - just the text area inside the border (adjusted lower)
34
- OCR_TEXT_COORDS = {
35
- 'x': 8, # Skip left border
36
- 'y': 116, # Moved down 4px for better text alignment (104 + 12)
37
- 'width': 224, # Skip both side borders (240 - 16)
38
- 'height': 36 # Reduced height to maintain bottom margin (56 - 20)
39
- }
40
-
41
- # Pokemon Emerald dialogue text colors (based on actual RGB values)
42
- DIALOGUE_TEXT_COLORS = [
43
- # Exact text color from user
44
- (99, 99, 99), # Exact text color
45
- # Close variations for anti-aliasing and slight rendering differences
46
- (95, 95, 95), # Slightly darker
47
- (103, 103, 103), # Slightly lighter
48
- (91, 91, 91), # Darker variant
49
- (107, 107, 107), # Lighter variant
50
- (99, 99, 95), # Slight color shift
51
- (99, 95, 99), # Slight color shift
52
- (95, 99, 99), # Slight color shift
53
- # Additional gray tones that might appear due to rendering
54
- (87, 87, 87), # Darker gray
55
- (111, 111, 111), # Lighter gray
56
- (79, 79, 79), # Much darker
57
- (119, 119, 119), # Much lighter
58
- # Shadow colors (darker, often with slight offset)
59
- (64, 64, 64), # Dark shadow
60
- (72, 72, 72), # Medium shadow
61
- (56, 56, 56), # Darker shadow
62
- (48, 48, 48), # Very dark shadow
63
- # Possible highlighting/special text colors
64
- (99, 99, 128), # Blue-tinted for names
65
- (128, 99, 99), # Red-tinted for special text
66
- (99, 128, 99), # Green-tinted for special text
67
- ]
68
-
69
- # Color tolerance for matching (RGB distance) - increased to capture more text pixels
70
- COLOR_TOLERANCE = 40
71
-
72
- # Pokemon Emerald dialogue box background colors (based on actual RGB values)
73
- DIALOGUE_BOX_BACKGROUND_COLORS = [
74
- # Exact green line/border color from user
75
- (85, 204, 128), # Exact green border color
76
- # Variations of the green border for anti-aliasing and shadows
77
- (80, 199, 123), # Slightly darker green
78
- (90, 209, 133), # Slightly lighter green
79
- (85, 204, 128), # Exact match (duplicate for emphasis)
80
- (75, 194, 118), # Darker green variant
81
- (95, 214, 138), # Lighter green variant
82
- # Exact white text background from user
83
- (255, 255, 255), # Exact white text background
84
- # Close variations for anti-aliasing and compression artifacts
85
- (254, 254, 254), # Very close to white
86
- (253, 253, 253), # Slightly off white
87
- (252, 252, 252), # Light gray-white
88
- (248, 248, 248), # Near white
89
- (240, 240, 240), # Light off-white
90
- (255, 255, 254), # Slight yellow tint
91
- (254, 255, 255), # Slight cyan tint
92
- ]
93
-
94
- # How much of the dialogue box should be background color to consider it "active"
95
- DIALOGUE_BOX_BACKGROUND_THRESHOLD = 0.4 # 40% of dialogue area should be box color (mostly off-white background)
96
-
97
- # Battle text area (different position)
98
- BATTLE_TEXT_COORDS = {
99
- 'x': 8,
100
- 'y': 120,
101
- 'width': 224,
102
- 'height': 40
103
- }
104
-
105
- def __init__(self):
106
- self.last_detected_text = ""
107
- self.text_stability_threshold = 2 # Frames text must be stable
108
- self.stable_text_count = 0
109
- self.debug_color_detection = False # Set to True for color debugging
110
- self.use_full_frame_scan = False # Set to True to enable full-frame scanning (may pick up noise)
111
- self.skip_dialogue_box_detection = False # Set to True to temporarily bypass dialogue box detection
112
-
113
- def detect_dialogue_from_screenshot(self, screenshot: Image.Image) -> Optional[str]:
114
- """
115
- Detect dialogue text from Pokemon Emerald dialogue regions only.
116
- First verifies dialogue box is visible to prevent false positives.
117
-
118
- Args:
119
- screenshot: PIL Image of the game screen
120
-
121
- Returns:
122
- Detected dialogue text or None if no text found
123
- """
124
- if not OCR_AVAILABLE:
125
- return None
126
-
127
- try:
128
- screenshot_np = np.array(screenshot)
129
-
130
- # STEP 1: Check if dialogue box is actually visible (unless bypassed)
131
- if not self.skip_dialogue_box_detection and not self.is_dialogue_box_visible(screenshot):
132
- logger.debug("No dialogue box detected - skipping OCR")
133
- return None
134
-
135
- # STEP 2: Primary dialogue box area (most common) - use tighter text coordinates
136
- dialogue_text = self._extract_text_from_region(
137
- screenshot_np,
138
- self.OCR_TEXT_COORDS
139
- )
140
-
141
- if dialogue_text:
142
- validated = self._validate_and_clean_text(dialogue_text)
143
- if validated:
144
- return validated
145
-
146
- # Method 2: Battle text area (different position)
147
- battle_text = self._extract_text_from_region(
148
- screenshot_np,
149
- self.BATTLE_TEXT_COORDS
150
- )
151
-
152
- if battle_text:
153
- validated = self._validate_and_clean_text(battle_text)
154
- if validated:
155
- return validated
156
-
157
- # Method 3: Full frame scan (only if explicitly enabled - can pick up noise)
158
- if self.use_full_frame_scan:
159
- full_frame_text = self._extract_text_from_full_frame(screenshot)
160
- if full_frame_text:
161
- validated = self._validate_and_clean_text(full_frame_text)
162
- if validated:
163
- return validated
164
-
165
- return None
166
-
167
- except Exception as e:
168
- logger.debug(f"OCR dialogue detection failed: {e}")
169
- return None
170
-
171
- def _extract_text_from_full_frame(self, screenshot: Image.Image) -> Optional[str]:
172
- """
173
- Extract text from the entire screenshot using OCR
174
- This is more comprehensive than region-specific detection
175
- """
176
- try:
177
- # Convert PIL to numpy array
178
- screenshot_np = np.array(screenshot)
179
-
180
- # Preprocess the entire frame for better OCR
181
- processed_frame = self._preprocess_full_frame_for_ocr(screenshot_np)
182
-
183
- # OCR configuration optimized for Pokemon text detection
184
- # Use different settings for full frame vs regions
185
- full_frame_config = r'--oem 3 --psm 6' # Assume uniform block of text
186
-
187
- # Extract text from entire frame
188
- full_text = pytesseract.image_to_string(processed_frame, config=full_frame_config)
189
-
190
- # Clean and validate the text
191
- cleaned_text = self._clean_full_frame_text(full_text)
192
-
193
- if cleaned_text:
194
- return cleaned_text
195
-
196
- # If that fails, try with different PSM mode
197
- alt_config = r'--oem 3 --psm 11' # Sparse text, find as much as possible
198
- alt_text = pytesseract.image_to_string(processed_frame, config=alt_config)
199
- alt_cleaned = self._clean_full_frame_text(alt_text)
200
-
201
- return alt_cleaned if alt_cleaned else None
202
-
203
- except Exception as e:
204
- logger.debug(f"Full frame OCR failed: {e}")
205
- return None
206
-
207
- def _preprocess_full_frame_for_ocr(self, image_np: np.ndarray) -> np.ndarray:
208
- """Preprocess entire frame using Pokemon-specific dialogue color matching"""
209
- # Ensure we have color information
210
- if len(image_np.shape) != 3:
211
- # Convert grayscale to color by duplicating channels
212
- image_np = cv2.cvtColor(image_np, cv2.COLOR_GRAY2RGB)
213
-
214
- # Scale up for better color detection precision
215
- scaled = cv2.resize(image_np, None, fx=3, fy=3, interpolation=cv2.INTER_CUBIC)
216
-
217
- # Create mask for dialogue text colors across entire frame
218
- text_mask = self._create_dialogue_color_mask(scaled)
219
-
220
- # Apply color mask - black text on white background (better for OCR)
221
- binary = np.where(text_mask, 0, 255).astype(np.uint8)
222
-
223
- # Enhanced morphological operations for full frame
224
- # Close gaps and thicken text
225
- kernel_close = np.ones((2, 2), np.uint8)
226
- cleaned = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel_close)
227
-
228
- # Dilate to make text more readable
229
- kernel_dilate = np.ones((1, 1), np.uint8)
230
- cleaned = cv2.dilate(cleaned, kernel_dilate, iterations=1)
231
-
232
- return cleaned
233
-
234
- def _clean_full_frame_text(self, raw_text: str) -> Optional[str]:
235
- """Clean and validate text extracted from full frame"""
236
- if not raw_text:
237
- return None
238
-
239
- # Remove excessive whitespace and special characters
240
- lines = []
241
- for line in raw_text.split('\n'):
242
- # Clean each line
243
- cleaned_line = re.sub(r'\s+', ' ', line.strip())
244
-
245
- # Filter out lines that are likely noise
246
- if len(cleaned_line) >= 2: # Minimum meaningful length
247
- # Check if line has reasonable character content
248
- alpha_ratio = sum(c.isalpha() for c in cleaned_line) / len(cleaned_line)
249
- if alpha_ratio >= 0.3: # At least 30% alphabetic characters
250
- lines.append(cleaned_line)
251
-
252
- if not lines:
253
- return None
254
-
255
- # Join lines and do final cleanup
256
- full_text = ' '.join(lines)
257
-
258
- # Remove common OCR artifacts for Pokemon games
259
- # These are characters commonly misread by OCR
260
- ocr_artifacts = [
261
- r'[|\\/_]', # Common line artifacts
262
- r'^\W+', # Leading non-word characters
263
- r'\W+$', # Trailing non-word characters
264
- ]
265
-
266
- for artifact in ocr_artifacts:
267
- full_text = re.sub(artifact, ' ', full_text)
268
-
269
- # Final cleanup
270
- full_text = re.sub(r'\s+', ' ', full_text).strip()
271
-
272
- # Validate final result
273
- if len(full_text) < 3:
274
- return None
275
-
276
- # Check for reasonable content (not just numbers/symbols)
277
- alpha_count = sum(c.isalpha() for c in full_text)
278
- if alpha_count < 3: # Need at least 3 letters
279
- return None
280
-
281
- return full_text
282
-
283
- def detect_all_text_regions(self, screenshot: Image.Image) -> List[dict]:
284
- """
285
- Detect all text regions in the screenshot with their locations
286
- Useful for debugging and comprehensive text detection
287
- """
288
- if not OCR_AVAILABLE:
289
- return []
290
-
291
- try:
292
- # Convert to numpy array
293
- screenshot_np = np.array(screenshot)
294
- processed = self._preprocess_full_frame_for_ocr(screenshot_np)
295
-
296
- # Use pytesseract to get text with bounding boxes
297
- data = pytesseract.image_to_data(processed, output_type=pytesseract.Output.DICT)
298
-
299
- text_regions = []
300
- n_boxes = len(data['level'])
301
-
302
- for i in range(n_boxes):
303
- # Get confidence and text
304
- confidence = int(data['conf'][i])
305
- text = data['text'][i].strip()
306
-
307
- # Only include text with reasonable confidence and content
308
- if confidence > 30 and len(text) > 1:
309
- # Get bounding box (scale back from 2x preprocessing)
310
- x = data['left'][i] // 2 # Scale back from 2x
311
- y = data['top'][i] // 2
312
- w = data['width'][i] // 2
313
- h = data['height'][i] // 2
314
-
315
- # Validate text content
316
- alpha_ratio = sum(c.isalpha() for c in text) / len(text)
317
- if alpha_ratio >= 0.3: # At least 30% letters
318
- text_regions.append({
319
- 'text': text,
320
- 'confidence': confidence,
321
- 'bbox': (x, y, w, h),
322
- 'area': w * h
323
- })
324
-
325
- # Sort by confidence and area (larger, more confident regions first)
326
- text_regions.sort(key=lambda r: (r['confidence'], r['area']), reverse=True)
327
-
328
- return text_regions
329
-
330
- except Exception as e:
331
- logger.debug(f"Text region detection failed: {e}")
332
- return []
333
-
334
- def _extract_text_from_region(self, image_np: np.ndarray, coords: dict) -> str:
335
- """Extract text from a specific region of the image"""
336
- # Extract region of interest
337
- y1 = coords['y']
338
- y2 = y1 + coords['height']
339
- x1 = coords['x']
340
- x2 = x1 + coords['width']
341
-
342
- roi = image_np[y1:y2, x1:x2]
343
-
344
- # Preprocessing for better OCR accuracy
345
- roi = self._preprocess_for_ocr(roi)
346
-
347
- # OCR configuration optimized for Pokemon Emerald text
348
- custom_config = r'--oem 3 --psm 6'
349
-
350
- # Extract text
351
- text = pytesseract.image_to_string(roi, config=custom_config)
352
- return text.strip()
353
-
354
- def _preprocess_for_ocr(self, roi: np.ndarray) -> np.ndarray:
355
- """Preprocess image region using Pokemon-specific dialogue color matching"""
356
- # Keep original color information for color matching
357
- if len(roi.shape) != 3:
358
- # Convert grayscale back to color for processing (duplicate channels)
359
- roi = cv2.cvtColor(roi, cv2.COLOR_GRAY2RGB)
360
-
361
- # Scale up first for better color detection precision
362
- roi = cv2.resize(roi, None, fx=4, fy=4, interpolation=cv2.INTER_CUBIC)
363
-
364
- # Create mask for dialogue text colors
365
- text_mask = self._create_dialogue_color_mask(roi)
366
-
367
- # Apply color mask to create clean binary image
368
- # Black text on white background (better for OCR)
369
- binary_roi = np.where(text_mask, 0, 255).astype(np.uint8)
370
-
371
- # Ensure we have a proper binary image (pure black and white only)
372
- binary_roi = np.where(binary_roi > 127, 255, 0).astype(np.uint8)
373
-
374
- # Enhanced morphological operations to thicken and connect text
375
- # Close gaps in letters
376
- kernel_close = np.ones((2, 2), np.uint8)
377
- binary_roi = cv2.morphologyEx(binary_roi, cv2.MORPH_CLOSE, kernel_close)
378
-
379
- # Dilate to make text thicker and more readable (balanced approach)
380
- kernel_dilate = np.ones((2, 2), np.uint8)
381
- binary_roi = cv2.dilate(binary_roi, kernel_dilate, iterations=2)
382
-
383
- # Remove small noise while preserving text
384
- kernel_open = np.ones((1, 1), np.uint8)
385
- binary_roi = cv2.morphologyEx(binary_roi, cv2.MORPH_OPEN, kernel_open)
386
-
387
- return binary_roi
388
-
389
- def _create_dialogue_color_mask(self, image: np.ndarray) -> np.ndarray:
390
- """Create binary mask for pixels matching Pokemon dialogue text colors"""
391
- if len(image.shape) != 3:
392
- return np.zeros(image.shape[:2], dtype=bool)
393
-
394
- mask = np.zeros(image.shape[:2], dtype=bool)
395
- matched_pixels_per_color = []
396
-
397
- # Check each dialogue color
398
- for i, target_color in enumerate(self.DIALOGUE_TEXT_COLORS):
399
- # Calculate color distance for all pixels
400
- color_diff = np.sqrt(np.sum((image - target_color) ** 2, axis=2))
401
-
402
- # Add pixels within tolerance to mask
403
- color_mask = (color_diff <= self.COLOR_TOLERANCE)
404
- mask |= color_mask
405
-
406
- # Debug information
407
- if self.debug_color_detection:
408
- matched_count = np.sum(color_mask)
409
- matched_pixels_per_color.append(matched_count)
410
-
411
- # Log color detection results for debugging
412
- if self.debug_color_detection and any(matched_pixels_per_color):
413
- total_matched = np.sum(mask)
414
- logger.debug(f"Color matching: {total_matched} pixels matched dialogue colors")
415
- for i, count in enumerate(matched_pixels_per_color):
416
- if count > 0:
417
- color = self.DIALOGUE_TEXT_COLORS[i]
418
- logger.debug(f" Color {color}: {count} pixels")
419
-
420
- return mask
421
-
422
- def is_dialogue_box_visible(self, screenshot: Image.Image) -> bool:
423
- """
424
- Check if a dialogue box is actually visible by looking for green horizontal border lines.
425
- Searches for the characteristic green lines above and below the dialogue text.
426
-
427
- Args:
428
- screenshot: PIL Image of the game screen
429
-
430
- Returns:
431
- True if dialogue box is detected, False otherwise
432
- """
433
- if not screenshot:
434
- return False
435
-
436
- try:
437
- # Convert to numpy array
438
- image_np = np.array(screenshot)
439
- if len(image_np.shape) != 3:
440
- return False
441
-
442
- # Extract extended dialogue region to catch border lines
443
- coords = self.DIALOGUE_BOX_COORDS
444
- # Extend the search area to catch top and bottom borders
445
- extended_region = image_np[
446
- max(0, coords['y'] - 5):min(image_np.shape[0], coords['y'] + coords['height'] + 5),
447
- coords['x']:coords['x'] + coords['width']
448
- ]
449
-
450
- if extended_region.size == 0:
451
- return False
452
-
453
- # Look for horizontal border lines using actual dialogue border colors
454
- border_colors = [
455
- (66, 181, 132), # Main teal border color from debug analysis
456
- (24, 165, 107), # Secondary border color
457
- (57, 140, 49), # Darker border variant
458
- (0, 255, 156), # Bright border accent
459
- (115, 198, 165) # Light border variant
460
- ]
461
- border_tolerance = 20 # Tolerance for color matching
462
-
463
- # Check each row for horizontal border lines
464
- border_line_rows = []
465
- height, width = extended_region.shape[:2]
466
-
467
- for row_idx in range(height):
468
- row_pixels = extended_region[row_idx]
469
-
470
- # Count border color pixels in this row
471
- border_pixels_in_row = 0
472
- for pixel in row_pixels:
473
- # Check if pixel matches any of the border colors
474
- for border_color in border_colors:
475
- color_diff = np.sqrt(np.sum((pixel - np.array(border_color)) ** 2))
476
- if color_diff <= border_tolerance:
477
- border_pixels_in_row += 1
478
- break # Don't double-count pixels
479
-
480
- # If significant portion of row has border colors, it's likely a border line
481
- border_percentage = border_pixels_in_row / width
482
- if border_percentage > 0.2: # 20% of row width has border colors (lower threshold)
483
- border_line_rows.append(row_idx)
484
-
485
- # VERY strict detection to avoid false positives from environment colors
486
-
487
- # Require many border lines for robust detection
488
- has_sufficient_border_lines = len(border_line_rows) >= 5 # Need at least 5 border lines
489
-
490
- # MUST have top AND bottom border lines (no exceptions for false positive prevention)
491
- has_top_and_bottom_lines = False
492
- if len(border_line_rows) >= 3:
493
- # Check if we have lines at different heights (top and bottom)
494
- min_line = min(border_line_rows)
495
- max_line = max(border_line_rows)
496
- if max_line - min_line > 15: # Lines must be at least 15 pixels apart (very strict)
497
- has_top_and_bottom_lines = True
498
-
499
- # Additional check: look for proper dialogue box pattern (rectangular border)
500
- has_rectangular_pattern = False
501
- if len(border_line_rows) >= 5:
502
- # Check if we have border lines spread across the dialogue region
503
- height_quarter = height // 4
504
- top_lines = [r for r in border_line_rows if r < height_quarter]
505
- middle_lines = [r for r in border_line_rows if height_quarter <= r <= 3 * height_quarter]
506
- bottom_lines = [r for r in border_line_rows if r > 3 * height_quarter]
507
-
508
- # Must have lines in top AND bottom, and some in middle for a proper box
509
- if len(top_lines) >= 2 and len(bottom_lines) >= 2 and len(middle_lines) >= 1:
510
- has_rectangular_pattern = True
511
-
512
- # Extra check: ensure lines are actually horizontal (consistent across width)
513
- has_proper_horizontal_lines = False
514
- if len(border_line_rows) >= 3:
515
- # Check that border lines extend across significant width (not just scattered pixels)
516
- proper_lines = 0
517
- for row_idx in border_line_rows[:10]: # Check first 10 lines
518
- row_pixels = extended_region[row_idx]
519
- border_pixels_in_row = 0
520
- for pixel in row_pixels:
521
- for border_color in border_colors:
522
- color_diff = np.sqrt(np.sum((pixel - np.array(border_color)) ** 2))
523
- if color_diff <= border_tolerance:
524
- border_pixels_in_row += 1
525
- break
526
-
527
- # Line must span at least 50% of width to be considered a proper horizontal line
528
- if border_pixels_in_row / width > 0.5:
529
- proper_lines += 1
530
-
531
- if proper_lines >= 3: # Need at least 3 proper horizontal lines
532
- has_proper_horizontal_lines = True
533
-
534
- # Log detection results
535
- if self.debug_color_detection:
536
- logger.debug(f"Border line detection: Found {len(border_line_rows)} border horizontal lines")
537
- logger.debug(f"Line rows: {border_line_rows[:5]}") # Show first 5
538
- logger.debug(f"Has sufficient lines (≥5): {has_sufficient_border_lines}")
539
- logger.debug(f"Has top+bottom lines (≥15px apart): {has_top_and_bottom_lines}")
540
- logger.debug(f"Has rectangular pattern: {has_rectangular_pattern}")
541
- logger.debug(f"Has proper horizontal lines (≥50% width): {has_proper_horizontal_lines}")
542
-
543
- # Final check: look for actual dialogue box background (light/white area inside borders)
544
- has_dialogue_background = False
545
- if len(border_line_rows) >= 3:
546
- # Check middle area for dialogue background colors (light colors)
547
- middle_start = height // 4
548
- middle_end = 3 * height // 4
549
- middle_region = extended_region[middle_start:middle_end, width//4:3*width//4]
550
-
551
- if middle_region.size > 0:
552
- # Look for light background colors typical of dialogue boxes
553
- light_pixels = 0
554
- total_pixels = middle_region.size // 3 # Divide by 3 for RGB
555
-
556
- for pixel in middle_region.reshape(-1, 3):
557
- # Light colors: high brightness (sum of RGB > 400) or white-ish
558
- brightness = np.sum(pixel)
559
- if brightness > 400 or (pixel[0] > 200 and pixel[1] > 200 and pixel[2] > 200):
560
- light_pixels += 1
561
-
562
- light_percentage = light_pixels / total_pixels
563
- if light_percentage > 0.3: # At least 30% of middle area should be light (dialogue background)
564
- has_dialogue_background = True
565
-
566
- # Log all criteria
567
- if self.debug_color_detection:
568
- logger.debug(f"Has dialogue background (light area): {has_dialogue_background}")
569
-
570
- # Use simplified detection method to avoid false positives
571
- # Check for white background in center area
572
- center_h = extended_region.shape[0] // 2
573
- center_w = extended_region.shape[1] // 2
574
- margin = 20
575
-
576
- center_area = extended_region[
577
- max(0, center_h - margin):min(extended_region.shape[0], center_h + margin),
578
- max(0, center_w - margin):min(extended_region.shape[1], center_w + margin)
579
- ]
580
-
581
- if center_area.size > 0:
582
- # Count white/light pixels (dialogue background)
583
- light_mask = (center_area[:,:,0] > 200) & (center_area[:,:,1] > 200) & (center_area[:,:,2] > 200)
584
- light_percentage = np.sum(light_mask) / light_mask.size
585
-
586
- # Count text-like colors (dark gray)
587
- text_mask = ((center_area[:,:,0] > 80) & (center_area[:,:,0] < 130) &
588
- (center_area[:,:,1] > 80) & (center_area[:,:,1] < 130) &
589
- (center_area[:,:,2] > 80) & (center_area[:,:,2] < 130))
590
- text_percentage = np.sum(text_mask) / text_mask.size
591
-
592
- # Simple, robust criteria
593
- is_visible = light_percentage > 0.3 and text_percentage > 0.02
594
-
595
- if self.debug_color_detection:
596
- logger.debug(f"Simplified detection - Light bg: {light_percentage:.1%}, Text: {text_percentage:.1%}")
597
- else:
598
- is_visible = False
599
-
600
- if self.debug_color_detection:
601
- logger.debug(f"Dialogue box {'VISIBLE' if is_visible else 'NOT VISIBLE'} "
602
- f"(found {len(border_line_rows)} border lines)")
603
-
604
- return is_visible
605
-
606
- except Exception as e:
607
- logger.debug(f"Dialogue box detection error: {e}")
608
- return False
609
-
610
- def enable_color_debug(self, enabled: bool = True):
611
- """Enable/disable color detection debugging"""
612
- self.debug_color_detection = enabled
613
- if enabled:
614
- logger.info("OCR color detection debugging enabled")
615
- else:
616
- logger.info("OCR color detection debugging disabled")
617
-
618
- def analyze_dialogue_colors(self, screenshot: Image.Image) -> dict:
619
- """
620
- Analyze a screenshot to find the actual colors used in the dialogue box.
621
- This helps fine-tune the DIALOGUE_TEXT_COLORS list.
622
- """
623
- if not screenshot:
624
- return {}
625
-
626
- # Convert to numpy array
627
- image_np = np.array(screenshot)
628
- if len(image_np.shape) != 3:
629
- return {}
630
-
631
- # Extract dialogue region
632
- coords = self.DIALOGUE_BOX_COORDS
633
- dialogue_region = image_np[
634
- coords['y']:coords['y'] + coords['height'],
635
- coords['x']:coords['x'] + coords['width']
636
- ]
637
-
638
- if dialogue_region.size == 0:
639
- return {}
640
-
641
- # Find unique colors and their frequencies
642
- pixels = dialogue_region.reshape(-1, 3)
643
- unique_colors, counts = np.unique(pixels, axis=0, return_counts=True)
644
-
645
- # Sort by frequency (most common first)
646
- sorted_indices = np.argsort(counts)[::-1]
647
-
648
- # Analyze the most common colors
649
- color_analysis = {
650
- 'total_pixels': len(pixels),
651
- 'unique_colors': len(unique_colors),
652
- 'top_colors': []
653
- }
654
-
655
- # Show top 20 most common colors
656
- for i in range(min(20, len(unique_colors))):
657
- idx = sorted_indices[i]
658
- color = tuple(unique_colors[idx])
659
- count = counts[idx]
660
- percentage = (count / len(pixels)) * 100
661
-
662
- color_analysis['top_colors'].append({
663
- 'rgb': color,
664
- 'count': int(count),
665
- 'percentage': round(percentage, 2)
666
- })
667
-
668
- return color_analysis
669
-
670
- def print_color_analysis(self, screenshot: Image.Image):
671
- """Print color analysis in a readable format"""
672
- analysis = self.analyze_dialogue_colors(screenshot)
673
-
674
- if not analysis:
675
- print("❌ Could not analyze colors")
676
- return
677
-
678
- print(f"\n🎨 DIALOGUE COLOR ANALYSIS")
679
- print(f"={'='*50}")
680
- print(f"Total pixels: {analysis['total_pixels']:,}")
681
- print(f"Unique colors: {analysis['unique_colors']:,}")
682
- print(f"\nTop Colors (most frequent first):")
683
- print(f"{'Rank':<4} {'RGB Color':<20} {'Count':<8} {'%':<6} {'Color Type':<15}")
684
- print(f"{'-'*70}")
685
-
686
- for i, color_info in enumerate(analysis['top_colors'][:15], 1):
687
- rgb = color_info['rgb']
688
- count = color_info['count']
689
- pct = color_info['percentage']
690
-
691
- # Classify the color
692
- if rgb[0] > 240 and rgb[1] > 240 and rgb[2] > 240:
693
- color_type = "Background"
694
- elif rgb[0] < 120 and rgb[1] < 120 and rgb[2] < 120:
695
- color_type = "Text/Shadow"
696
- elif abs(rgb[0] - rgb[1]) < 10 and abs(rgb[1] - rgb[2]) < 10:
697
- color_type = "Gray text"
698
- else:
699
- color_type = "Other"
700
-
701
- print(f"{i:<4} {str(rgb):<20} {count:<8} {pct:<6.1f} {color_type:<15}")
702
-
703
- print(f"\n💡 Suggested dialogue colors to add:")
704
- suggested = []
705
- for color_info in analysis['top_colors'][:10]:
706
- rgb = color_info['rgb']
707
- # Suggest colors that look like text (not pure white background)
708
- if rgb[0] < 200 and color_info['percentage'] > 0.5:
709
- suggested.append(rgb)
710
-
711
- for color in suggested[:5]: # Show top 5 suggestions
712
- print(f" {color},")
713
-
714
- print(f"{'='*50}")
715
-
716
- def update_dialogue_colors_from_analysis(self, screenshot: Image.Image, threshold_percentage: float = 1.0):
717
- """
718
- Update DIALOGUE_TEXT_COLORS based on analysis of actual screenshot.
719
- Only adds colors that appear frequently enough (above threshold_percentage).
720
- """
721
- analysis = self.analyze_dialogue_colors(screenshot)
722
-
723
- if not analysis:
724
- logger.warning("Could not analyze colors to update dialogue colors")
725
- return
726
-
727
- # Find colors that appear frequently and look like text
728
- new_colors = []
729
- for color_info in analysis['top_colors']:
730
- rgb = color_info['rgb']
731
- pct = color_info['percentage']
732
-
733
- # Only consider colors that:
734
- # 1. Appear frequently enough
735
- # 2. Are not pure white (background)
736
- # 3. Are not already in our color list
737
- if (pct >= threshold_percentage and
738
- not (rgb[0] > 240 and rgb[1] > 240 and rgb[2] > 240) and
739
- rgb not in self.DIALOGUE_TEXT_COLORS):
740
- new_colors.append(rgb)
741
-
742
- if new_colors:
743
- logger.info(f"Adding {len(new_colors)} new dialogue colors from analysis")
744
- for color in new_colors[:5]: # Limit to top 5 new colors
745
- logger.info(f" Added color: {color}")
746
-
747
- # Add new colors to the existing list
748
- self.DIALOGUE_TEXT_COLORS.extend(new_colors[:5])
749
- else:
750
- logger.info("No new dialogue colors found to add")
751
-
752
- def analyze_dialogue_box_background(self, screenshot: Image.Image):
753
- """
754
- Analyze dialogue box region to find actual background colors.
755
- Useful for fine-tuning DIALOGUE_BOX_BACKGROUND_COLORS.
756
- """
757
- analysis = self.analyze_dialogue_colors(screenshot)
758
-
759
- if not analysis:
760
- print("❌ Could not analyze dialogue box background")
761
- return
762
-
763
- print(f"\n📦 DIALOGUE BOX BACKGROUND ANALYSIS")
764
- print(f"{'='*50}")
765
- print(f"Total pixels: {analysis['total_pixels']:,}")
766
- print(f"Unique colors: {analysis['unique_colors']:,}")
767
- print(f"\nTop Background Colors (most frequent first):")
768
- print(f"{'Rank':<4} {'RGB Color':<20} {'Count':<8} {'%':<6} {'Type':<15}")
769
- print(f"{'-'*70}")
770
-
771
- for i, color_info in enumerate(analysis['top_colors'][:15], 1):
772
- rgb = color_info['rgb']
773
- count = color_info['count']
774
- pct = color_info['percentage']
775
-
776
- # Classify as likely background vs text
777
- if pct > 10: # Very common = likely background
778
- color_type = "Background"
779
- elif rgb[0] < 150 and rgb[1] < 150 and rgb[2] < 150:
780
- color_type = "Text/Shadow"
781
- else:
782
- color_type = "Other"
783
-
784
- print(f"{i:<4} {str(rgb):<20} {count:<8} {pct:<6.1f} {color_type:<15}")
785
-
786
- print(f"\n💡 Suggested background colors (>5% pixels):")
787
- for color_info in analysis['top_colors'][:10]:
788
- rgb = color_info['rgb']
789
- pct = color_info['percentage']
790
- # Suggest colors that are common and not text-like
791
- if pct > 5.0 and not (rgb[0] < 150 and rgb[1] < 150 and rgb[2] < 150):
792
- print(f" {rgb},")
793
-
794
- print(f"{'='*50}")
795
-
796
- def test_dialogue_box_detection(self, screenshot: Image.Image):
797
- """Test dialogue box detection with detailed output for green line method"""
798
- print(f"\n🔍 DIALOGUE BOX DETECTION TEST (Green Line Method)")
799
- print(f"{'='*50}")
800
-
801
- # Enable debug mode for detailed output
802
- old_debug = self.debug_color_detection
803
- self.debug_color_detection = True
804
-
805
- is_visible = self.is_dialogue_box_visible(screenshot)
806
-
807
- # Get detailed green line analysis
808
- image_np = np.array(screenshot)
809
- coords = self.DIALOGUE_BOX_COORDS
810
-
811
- # Extended region for border detection
812
- extended_region = image_np[
813
- max(0, coords['y'] - 5):min(image_np.shape[0], coords['y'] + coords['height'] + 5),
814
- coords['x']:coords['x'] + coords['width']
815
- ]
816
-
817
- height, width = extended_region.shape[:2]
818
- green_border_color = (85, 204, 128)
819
- green_tolerance = 15
820
-
821
- print(f"Search region: {coords['x']},{coords['y']-5} {coords['width']}x{height+10}")
822
- print(f"Green border color: {green_border_color}")
823
- print(f"Green tolerance: ±{green_tolerance}")
824
-
825
- # Analyze each row
826
- green_line_rows = []
827
- for row_idx in range(height):
828
- row_pixels = extended_region[row_idx]
829
-
830
- green_pixels_in_row = 0
831
- for pixel in row_pixels:
832
- color_diff = np.sqrt(np.sum((pixel - green_border_color) ** 2))
833
- if color_diff <= green_tolerance:
834
- green_pixels_in_row += 1
835
-
836
- green_percentage = green_pixels_in_row / width
837
- if green_percentage > 0.3: # 30% threshold
838
- green_line_rows.append({
839
- 'row': row_idx,
840
- 'green_pixels': green_pixels_in_row,
841
- 'percentage': green_percentage * 100
842
- })
843
-
844
- print(f"Found {len(green_line_rows)} green horizontal lines:")
845
- for line_info in green_line_rows[:5]: # Show first 5
846
- row = line_info['row']
847
- pixels = line_info['green_pixels']
848
- pct = line_info['percentage']
849
- print(f" Row {row}: {pixels}/{width} pixels ({pct:.1f}% green)")
850
-
851
- print(f"\nResult: {'✅ DIALOGUE BOX VISIBLE' if is_visible else '❌ NOT VISIBLE'}")
852
- print(f"{'='*50}")
853
-
854
- # Restore debug setting
855
- self.debug_color_detection = old_debug
856
-
857
- return is_visible
858
-
859
- def _validate_and_clean_text(self, text: str) -> Optional[str]:
860
- """Validate and clean detected text"""
861
- if not text or len(text.strip()) < 3:
862
- return None
863
-
864
- # Clean up common OCR errors
865
- text = re.sub(r'\n+', ' ', text) # Replace newlines with spaces
866
- text = re.sub(r'\s+', ' ', text) # Normalize whitespace
867
- text = text.strip()
868
-
869
- # Filter out obviously wrong detections
870
- if len(text) < 3 or len(text) > 200:
871
- return None
872
-
873
- # Check for minimum alphabetic content (avoid detecting UI elements)
874
- alpha_ratio = sum(c.isalpha() for c in text) / len(text)
875
- if alpha_ratio < 0.5:
876
- return None
877
-
878
- # Comprehensive random letter filtering - catch ANY nonsense patterns
879
- if self._is_random_nonsense(text):
880
- logger.debug(f"OCR validation: Rejected as random nonsense: '{text[:50]}...'")
881
- return None
882
-
883
- return text
884
-
885
- def _is_random_nonsense(self, text: str) -> bool:
886
- """
887
- Comprehensive detection of random letter sequences and nonsense text.
888
- Catches any type of random letters that don't form meaningful dialogue.
889
- """
890
- if not text or len(text.strip()) < 3:
891
- return True
892
-
893
- text_lower = text.lower().strip()
894
- words = text_lower.split()
895
-
896
- if len(words) == 0:
897
- return True
898
-
899
- # Pattern 1: Excessive single/double character "words"
900
- short_words = [w for w in words if len(w) <= 2]
901
- if len(short_words) > len(words) * 0.6: # More than 60% are very short
902
- return True
903
-
904
- # Pattern 2: Repetitive patterns (like "a a a a a")
905
- word_counts = {}
906
- for word in words:
907
- word_counts[word] = word_counts.get(word, 0) + 1
908
- for word, count in word_counts.items():
909
- if len(word) <= 2 and count >= 3: # Short word repeated 3+ times
910
- return True
911
-
912
- # Pattern 3: Too many words (dialogue is usually concise)
913
- if len(words) > 30:
914
- return True
915
-
916
- # Pattern 4: Check for valid English-like words
917
- valid_words = 0
918
- dialogue_words = {
919
- 'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by',
920
- 'you', 'i', 'we', 'they', 'he', 'she', 'it', 'this', 'that', 'these', 'those',
921
- 'is', 'are', 'was', 'were', 'be', 'been', 'being', 'have', 'has', 'had', 'do', 'does', 'did',
922
- 'will', 'would', 'could', 'should', 'can', 'may', 'might', 'must',
923
- 'get', 'got', 'give', 'take', 'go', 'come', 'see', 'look', 'want', 'need', 'know', 'think',
924
- 'pokemon', 'trainer', 'battle', 'items', 'store', 'pc', 'computer', 'use', 'hello', 'hi'
925
- }
926
-
927
- for word in words:
928
- clean_word = ''.join(c for c in word if c.isalnum()).lower()
929
- if len(clean_word) >= 2:
930
- # Check if it's a known good word
931
- if clean_word in dialogue_words:
932
- valid_words += 1
933
- # Check if it has reasonable letter patterns
934
- elif self._has_valid_letter_pattern(clean_word):
935
- valid_words += 1
936
-
937
- # Need at least 30% valid words
938
- valid_ratio = valid_words / len(words) if len(words) > 0 else 0
939
- if valid_ratio < 0.3:
940
- return True
941
-
942
- # Pattern 5: Detect excessive mixed case (OCR noise pattern)
943
- mixed_case_words = 0
944
- for word in words:
945
- if len(word) >= 3:
946
- has_lower = any(c.islower() for c in word)
947
- has_upper = any(c.isupper() for c in word)
948
- if has_lower and has_upper and not word[0].isupper(): # Not normal capitalization
949
- mixed_case_words += 1
950
-
951
- if mixed_case_words > len(words) * 0.4: # More than 40% have weird capitalization
952
- return True
953
-
954
- return False
955
-
956
- def _has_valid_letter_pattern(self, word: str) -> bool:
957
- """Check if word has valid English-like letter patterns"""
958
- if len(word) < 2:
959
- return False
960
-
961
- # Must have at least one vowel (unless very short)
962
- vowels = 'aeiou'
963
- has_vowel = any(c in vowels for c in word.lower())
964
- if len(word) >= 3 and not has_vowel:
965
- return False
966
-
967
- # Check for reasonable consonant clusters
968
- consonants = 'bcdfghjklmnpqrstvwxyz'
969
- consonant_streak = 0
970
- max_consonant_streak = 0
971
-
972
- for char in word.lower():
973
- if char in consonants:
974
- consonant_streak += 1
975
- max_consonant_streak = max(max_consonant_streak, consonant_streak)
976
- else:
977
- consonant_streak = 0
978
-
979
- # Too many consonants in a row suggests OCR noise
980
- if max_consonant_streak > 4:
981
- return False
982
-
983
- # Check for excessive repeated characters
984
- repeated = 0
985
- for i in range(len(word) - 1):
986
- if word[i] == word[i + 1]:
987
- repeated += 1
988
-
989
- if repeated > len(word) * 0.4: # More than 40% repeated chars
990
- return False
991
-
992
- return True
993
-
994
- def get_stable_dialogue_text(self, screenshot: Image.Image) -> Optional[str]:
995
- """
996
- Get dialogue text that has been stable across multiple frames.
997
- This helps avoid detecting transitional/partial text.
998
- """
999
- current_text = self.detect_dialogue_from_screenshot(screenshot)
1000
-
1001
- if current_text == self.last_detected_text:
1002
- self.stable_text_count += 1
1003
- else:
1004
- self.stable_text_count = 0
1005
- self.last_detected_text = current_text
1006
-
1007
- # Return text only if it's been stable for threshold frames
1008
- if self.stable_text_count >= self.text_stability_threshold and current_text:
1009
- return current_text
1010
-
1011
- return None
1012
-
1013
-
1014
- def create_ocr_detector() -> Optional[OCRDialogueDetector]:
1015
- """Factory function to create OCR detector if available"""
1016
- if OCR_AVAILABLE:
1017
- return OCRDialogueDetector()
1018
- else:
1019
- logger.warning("OCR not available - install pytesseract and tesseract-ocr system package")
1020
- return None