programasweights 0.1.0.dev5__tar.gz → 0.1.0.dev6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (332) hide show
  1. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/PKG-INFO +1 -1
  2. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights/__init__.py +1 -1
  3. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/pyproject.toml +1 -1
  4. programasweights-0.1.0.dev6/server/alembic/versions/002_namespaced_aliases_hf_url.py +37 -0
  5. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/api/models/orm.py +2 -1
  6. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/api/routes/compile.py +25 -2
  7. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/api/routes/programs.py +49 -28
  8. programasweights-0.1.0.dev6/server/api/services/storage_service.py +114 -0
  9. programasweights-0.1.0.dev6/server/scripts/cleanup_storage.py +66 -0
  10. programasweights-0.1.0.dev6/server/tests/test_storage.py +134 -0
  11. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/LandingPage.tsx +15 -15
  12. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/MainInterface.tsx +17 -9
  13. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/.gitignore +0 -0
  14. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/.hatch_build.toml +0 -0
  15. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/.readthedocs.yaml +0 -0
  16. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/1apple.jpg +0 -0
  17. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/1apple2.jpg +0 -0
  18. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/2apples.jpg +0 -0
  19. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/2apples2.jpg +0 -0
  20. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/3apples.jpg +0 -0
  21. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/3apples2.jpg +0 -0
  22. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/479400.png +0 -0
  23. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/4apples.jpg +0 -0
  24. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/4apples2.jpg +0 -0
  25. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/4apples3.jpg +0 -0
  26. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/4apples4.jpg +0 -0
  27. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/5apples.jpg +0 -0
  28. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/6apples.jpg +0 -0
  29. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/8apples.jpg +0 -0
  30. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/9apples.jpg +0 -0
  31. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/FLOW_SUMMARY.md +0 -0
  32. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/MANIFEST.in +0 -0
  33. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/ONNX_MIGRATION_PLAN.md +0 -0
  34. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/PREFIX_TOKENS_DESIGN.md +0 -0
  35. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/PYPI_README.md +0 -0
  36. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/README.md +0 -0
  37. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/TRUNCATION_CHANGES.md +0 -0
  38. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/USE_CASES_AND_IDEAS.md +0 -0
  39. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/VERIFICATION_USAGE.md +0 -0
  40. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/analyze_dataset.py +0 -0
  41. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/analyze_lengths.py +0 -0
  42. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/baselines/code_prompt.md +0 -0
  43. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/baselines/evaluate_openai_python_code_baseline.py +0 -0
  44. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/baselines/openai_batch_request.py +0 -0
  45. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/baselines/prepare_alchemist_data.py +0 -0
  46. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/baselines/prepare_var_bench_data.py +0 -0
  47. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/baselines/python_code_sandbox.py +0 -0
  48. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/baselines/script_evaluation_var_bench.sh +0 -0
  49. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/baselines/script_evalution_evaluation.sh +0 -0
  50. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/baselines/script_evalution_request.sh +0 -0
  51. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/baselines/script_evalution_statistics.sh +0 -0
  52. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/benchmark_pytorch_vs_onnx.py +0 -0
  53. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/benchmark_user_experience.py +0 -0
  54. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/check_dataset.py +0 -0
  55. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/combine_datasets.py +0 -0
  56. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/compare_datasets.py +0 -0
  57. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/compare_old_vs_regen.py +0 -0
  58. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/convert_paw_to_svg.py +0 -0
  59. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/create_favicon_sizes.py +0 -0
  60. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/create_visualization_from_log.py +0 -0
  61. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/create_vqa_dataset.py +0 -0
  62. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/debug_cache.py +0 -0
  63. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/debug_eos_example.sh +0 -0
  64. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/docs/Makefile +0 -0
  65. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/docs/adr/001-llama-cpp-over-pytorch.md +0 -0
  66. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/docs/adr/002-q4_0-adapter-format.md +0 -0
  67. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/docs/adr/003-single-spec-field.md +0 -0
  68. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/docs/adr/004-compiler-naming.md +0 -0
  69. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/docs/adr/005-vllm-hidden-states.md +0 -0
  70. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/docs/adr/006-email-api-key-auth.md +0 -0
  71. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/docs/api-reference.rst +0 -0
  72. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/docs/architecture.md +0 -0
  73. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/docs/conf.py +0 -0
  74. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/docs/examples/evaluation-tasks.rst +0 -0
  75. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/docs/index.rst +0 -0
  76. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/docs/installation.rst +0 -0
  77. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/docs/make.bat +0 -0
  78. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/docs/quickstart.rst +0 -0
  79. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/docs/requirements.txt +0 -0
  80. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/docs/using-pretrained.rst +0 -0
  81. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/estimate_data_gen_cost.py +0 -0
  82. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/eval.py +0 -0
  83. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/examples/flask_app.py +0 -0
  84. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/examples/jupyter_notebook.py +0 -0
  85. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/examples/langchain_integration.py +0 -0
  86. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/examples/replace_openai.py +0 -0
  87. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/export_to_onnx.py +0 -0
  88. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/extract_models.py +0 -0
  89. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/inspect_data_dirs.py +0 -0
  90. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/latest_export.csv +0 -0
  91. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/log.train.81920.morecategories.extraprefix +0 -0
  92. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/main_no_spec_direct_ans_mix_continuous_sampleref_shorterprompt_vllm.py +0 -0
  93. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/merge_datasets.py +0 -0
  94. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/paw.png +0 -0
  95. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/paw.svg +0 -0
  96. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/process_im2latex_dataset.py +0 -0
  97. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights/artifacts.py +0 -0
  98. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights/cache.py +0 -0
  99. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights/cli.py +0 -0
  100. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights/client.py +0 -0
  101. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights/compiler/__init__.py +0 -0
  102. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights/compiler/dummy.py +0 -0
  103. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights/config.py +0 -0
  104. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights/convert_peft_to_paw.py +0 -0
  105. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights/paw_format.py +0 -0
  106. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights/runtime/__init__.py +0 -0
  107. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights/runtime/interpreter.py +0 -0
  108. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights/runtime/interpreter_onnx.py +0 -0
  109. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights/runtime_llamacpp.py +0 -0
  110. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights_lora/__init__.py +0 -0
  111. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights_lora/compiler/__init__.py +0 -0
  112. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights_lora/lora_format.py +0 -0
  113. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights_lora/runtime/__init__.py +0 -0
  114. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights_lora/runtime/interpreter_lora.py +0 -0
  115. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights_lora/tests/test_compile_and_run.py +0 -0
  116. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights_lora/tests/test_lora_format.py +0 -0
  117. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights_lora/tests/test_training.py +0 -0
  118. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights_lora/train_lora.py +0 -0
  119. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights_lora/training/__init__.py +0 -0
  120. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/programasweights_lora/training/loops/lora_tuning_sft.py +0 -0
  121. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/run_eval.sh +0 -0
  122. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/run_training.sh +0 -0
  123. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/scripts/filter_table_by_length.py +0 -0
  124. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/.env.example +0 -0
  125. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/alembic/env.py +0 -0
  126. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/alembic/script.py.mako +0 -0
  127. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/alembic/versions/001_initial_schema.py +0 -0
  128. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/alembic.ini +0 -0
  129. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/api/__init__.py +0 -0
  130. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/api/config.py +0 -0
  131. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/api/dependencies.py +0 -0
  132. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/api/logging_config.py +0 -0
  133. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/api/main.py +0 -0
  134. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/api/models/__init__.py +0 -0
  135. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/api/models/database.py +0 -0
  136. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/api/models/schemas.py +0 -0
  137. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/api/routes/__init__.py +0 -0
  138. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/api/routes/auth.py +0 -0
  139. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/api/routes/health.py +0 -0
  140. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/api/routes/infer.py +0 -0
  141. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/api/routes/models_info.py +0 -0
  142. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/api/services/__init__.py +0 -0
  143. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/api/services/compile_service.py +0 -0
  144. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/api/services/infer_service.py +0 -0
  145. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/benchmarks/benchmark_api.py +0 -0
  146. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/benchmarks/handcrafted_specs.json +0 -0
  147. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/benchmarks/last_benchmark_results.json +0 -0
  148. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/benchmarks/last_stress_results.json +0 -0
  149. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/benchmarks/stress_test.py +0 -0
  150. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/requirements.txt +0 -0
  151. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/scripts/start_services.sh +0 -0
  152. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/tests/__init__.py +0 -0
  153. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/tests/conftest.py +0 -0
  154. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/tests/test_auth.py +0 -0
  155. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/tests/test_compile.py +0 -0
  156. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/tests/test_errors.py +0 -0
  157. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/tests/test_infer.py +0 -0
  158. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/tests/test_integration_gpu.py +0 -0
  159. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/tests/test_rate_limit.py +0 -0
  160. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/vllm_models/__init__.py +0 -0
  161. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/vllm_models/paw_compiler.py +0 -0
  162. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/vllm_models/prepare_checkpoint.py +0 -0
  163. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/server/vllm_models/register.py +0 -0
  164. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/stage2_firstpromptqwen_512_e1_generate_lora_e2grpo_overfit_one_debug.reward_plot.rollout_ppl.png +0 -0
  165. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/stage2_firstpromptqwen_512_e1_generate_lora_e2grpo_overfit_one_debug.reward_plot.train_gt_logprob.em_es.png +0 -0
  166. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/stage2_firstpromptqwen_512_e1_generate_lora_e2grpo_overfit_one_debug.reward_plot.train_gt_logprob.ppl.png +0 -0
  167. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/stage2_firstpromptqwen_512_e1_generate_lora_e2grpo_overfit_one_debug.reward_plot.train_gt_logprob.reward.png +0 -0
  168. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/test_1spec.py +0 -0
  169. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/test_all_caching.py +0 -0
  170. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/test_apple_count.py +0 -0
  171. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/test_batch_pilot.py +0 -0
  172. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/test_compile.py +0 -0
  173. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/test_e2e.py +0 -0
  174. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/test_execute.py +0 -0
  175. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/test_nspecs.py +0 -0
  176. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/test_one_vs_two_step.py +0 -0
  177. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/test_onnx_correctness.py +0 -0
  178. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/test_onnx_hf_model.py +0 -0
  179. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/test_onnx_hf_with_images.py +0 -0
  180. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/test_paw_format.py +0 -0
  181. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/test_thinking_comparison.py +0 -0
  182. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/tests/test_programasweights.py +0 -0
  183. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/train.py +0 -0
  184. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/train_no_spec_direct_ans_mix_continuous_sampleref_trainonly_shorterprompt_withregularizer_generate_lora.py +0 -0
  185. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/README.md +0 -0
  186. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/__init__.py +0 -0
  187. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/DATASET_CHANGELOG.md +0 -0
  188. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/README.md +0 -0
  189. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/VERIFICATION_PIPELINE.md +0 -0
  190. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/dry_run_batch.py +0 -0
  191. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/filter_test_data.py +0 -0
  192. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/generate_specs.py +0 -0
  193. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/generate_specs_batch.py +0 -0
  194. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/incremental_merge.py +0 -0
  195. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/merge_and_upload.py +0 -0
  196. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/regenerate_outputs_batch.py +0 -0
  197. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/synthesize_data.py +0 -0
  198. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/synthesize_data_batch.py +0 -0
  199. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates/filter_system.txt +0 -0
  200. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates/filter_user.txt +0 -0
  201. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates/pairs_system.txt +0 -0
  202. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates/pairs_user.txt +0 -0
  203. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates/specs_system.txt +0 -0
  204. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates/specs_user.txt +0 -0
  205. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates/specs_user_freeform.txt +0 -0
  206. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates/specs_user_freeform_with_examples.txt +0 -0
  207. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates/specs_user_with_examples.txt +0 -0
  208. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates/verify_system.txt +0 -0
  209. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates/verify_user.txt +0 -0
  210. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates_old/filter_system.txt +0 -0
  211. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates_old/filter_user.txt +0 -0
  212. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates_old/pairs_system.txt +0 -0
  213. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates_old/pairs_user.txt +0 -0
  214. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates_old/specs_system.txt +0 -0
  215. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates_old/specs_user.txt +0 -0
  216. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates_old/specs_user_freeform.txt +0 -0
  217. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates_old/specs_user_freeform_with_examples.txt +0 -0
  218. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates_old/specs_user_with_examples.txt +0 -0
  219. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates_old/verify_system.txt +0 -0
  220. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/templates_old/verify_user.txt +0 -0
  221. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/data_generation/verify_test_data.py +0 -0
  222. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/datasets/__init__.py +0 -0
  223. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/datasets/jsonl_text_pairs.py +0 -0
  224. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/loops/__init__.py +0 -0
  225. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/training/loops/prefix_tuning_sft.py +0 -0
  226. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/ttt.py +0 -0
  227. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/upload_model.py +0 -0
  228. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/upload_onnx_to_huggingface.py +0 -0
  229. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/upload_onnx_to_huggingface_with_token.py +0 -0
  230. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/utils.py +0 -0
  231. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/HANDOFF.md +0 -0
  232. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/README.md +0 -0
  233. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/app/__init__.py +0 -0
  234. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/app/config.py +0 -0
  235. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/app/main.py +0 -0
  236. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/app/middleware/__init__.py +0 -0
  237. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/app/middleware/rate_limit.py +0 -0
  238. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/app/models.py +0 -0
  239. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/app/services/__init__.py +0 -0
  240. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/app/services/auth_service.py +0 -0
  241. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/app/services/case_service.py +0 -0
  242. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/app/services/compiler_service.py +0 -0
  243. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/app/services/gpt_service.py +0 -0
  244. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/app/services/hub_service.py +0 -0
  245. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/app/services/image_service.py +0 -0
  246. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/app/services/interpreter_service.py +0 -0
  247. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/app/services/sql_manager.py +0 -0
  248. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/app/templates/gpt_test_generation.txt +0 -0
  249. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/app/utils/__init__.py +0 -0
  250. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/app/utils/image_placeholders.py +0 -0
  251. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/app/utils/program_hash.py +0 -0
  252. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/clear_db.sh +0 -0
  253. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/clear_tables.sql +0 -0
  254. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/data/programs.db +0 -0
  255. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/env_example.txt +0 -0
  256. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/example_images/README.md +0 -0
  257. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/get_data_examples.py +0 -0
  258. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/requirements.txt +0 -0
  259. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/run_server.py +0 -0
  260. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/setup_analytics_tables.sql +0 -0
  261. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/setup_auth_tables.sql +0 -0
  262. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/setup_cache_tables.sql +0 -0
  263. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/setup_cases_tables.sql +0 -0
  264. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/setup_database.sql +0 -0
  265. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/setup_database_simple.sql +0 -0
  266. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/setup_db.sh +0 -0
  267. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/setup_example_images.py +0 -0
  268. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/setup_hub_tables.sql +0 -0
  269. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/backend/test_compilation_cache.py +0 -0
  270. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/README.md +0 -0
  271. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/eslint.config.js +0 -0
  272. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/index.html +0 -0
  273. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/package-lock.json +0 -0
  274. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/package.json +0 -0
  275. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/postcss.config.js +0 -0
  276. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/public/apple-touch-icon.png +0 -0
  277. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/public/favicon-16x16.png +0 -0
  278. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/public/favicon-32x32.png +0 -0
  279. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/public/paw-192.png +0 -0
  280. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/public/paw-512.png +0 -0
  281. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/public/paw.svg +0 -0
  282. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/public/react-test.html +0 -0
  283. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/public/test.html +0 -0
  284. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/public/vite.svg +0 -0
  285. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/App.css +0 -0
  286. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/App.tsx +0 -0
  287. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/assets/react.svg +0 -0
  288. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/AboutPage.tsx +0 -0
  289. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/AutoTestSection.tsx +0 -0
  290. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/CasesSection.tsx +0 -0
  291. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/CollapsibleExamples.tsx +0 -0
  292. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/CompileButtonWithConfig.tsx +0 -0
  293. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/CompileSection.tsx +0 -0
  294. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/CopyCodeSection.tsx +0 -0
  295. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/DocsPage.tsx +0 -0
  296. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/ExampleRow/ExampleRowEditor.tsx +0 -0
  297. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/ExamplesInput.tsx +0 -0
  298. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/Footer.tsx +0 -0
  299. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/Header.tsx +0 -0
  300. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/HubPage.tsx +0 -0
  301. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/HubProgramPage.tsx +0 -0
  302. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/HubUploadPage.tsx +0 -0
  303. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/ImageUpload.tsx +0 -0
  304. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/InputBlocks/ImageBlock.tsx +0 -0
  305. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/InputBlocks/InputBlockList.tsx +0 -0
  306. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/InputBlocks/TextBlock.tsx +0 -0
  307. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/LeaderboardPage.tsx +0 -0
  308. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/ModelSelector.tsx +0 -0
  309. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/MultiImageUpload.tsx +0 -0
  310. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/PricingPage.tsx +0 -0
  311. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/PrivacyPage.tsx +0 -0
  312. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/ProfilePage.tsx +0 -0
  313. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/ProgramDetailPage.tsx +0 -0
  314. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/PublishProgramPage.tsx +0 -0
  315. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/SpecInput.tsx +0 -0
  316. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/TermsPage.tsx +0 -0
  317. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/components/TestSection.tsx +0 -0
  318. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/index.css +0 -0
  319. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/main.tsx +0 -0
  320. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/types/index.ts +0 -0
  321. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/src/utils/api.ts +0 -0
  322. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/tailwind.config.js +0 -0
  323. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/tsconfig.app.json +0 -0
  324. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/tsconfig.json +0 -0
  325. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/tsconfig.node.json +0 -0
  326. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/frontend/vite.config.ts +0 -0
  327. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/nginx-paw.conf +0 -0
  328. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/nginx.conf +0 -0
  329. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/setup_mysql.sh +0 -0
  330. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/start.sh +0 -0
  331. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/test_setup.py +0 -0
  332. {programasweights-0.1.0.dev5 → programasweights-0.1.0.dev6}/web-app/ttt.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: programasweights
3
- Version: 0.1.0.dev5
3
+ Version: 0.1.0.dev6
4
4
  Summary: Compile natural language specifications into neural programs that run locally via llama.cpp.
5
5
  Author-email: ProgramAsWeights <support@programasweights.com>
6
6
  License: MIT
@@ -19,7 +19,7 @@ API reference:
19
19
  paw.api_key API key (set via login() or PAW_API_KEY env var)
20
20
  """
21
21
 
22
- __version__ = "0.1.0.dev5"
22
+ __version__ = "0.1.0.dev6"
23
23
 
24
24
  from .config import get_api_url, get_api_key, set_api_key
25
25
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "programasweights"
7
- version = "0.1.0.dev5"
7
+ version = "0.1.0.dev6"
8
8
  description = "Compile natural language specifications into neural programs that run locally via llama.cpp."
9
9
  readme = "PYPI_README.md"
10
10
  requires-python = ">=3.9"
@@ -0,0 +1,37 @@
1
+ """Add hf_url to programs, widen alias slug for username/name format
2
+
3
+ Revision ID: 002
4
+ Revises: 001
5
+ Create Date: 2026-03-26
6
+ """
7
+ from typing import Sequence, Union
8
+
9
+ from alembic import op
10
+ import sqlalchemy as sa
11
+
12
+ revision: str = "002"
13
+ down_revision: Union[str, None] = "001"
14
+ branch_labels: Union[str, Sequence[str], None] = None
15
+ depends_on: Union[str, Sequence[str], None] = None
16
+
17
+
18
+ def upgrade() -> None:
19
+ op.add_column("programs", sa.Column("hf_url", sa.Text, nullable=True))
20
+ op.alter_column("aliases", "slug", type_=sa.String(120))
21
+ op.drop_constraint("ck_alias_slug_format", "aliases", type_="check")
22
+ op.create_check_constraint(
23
+ "ck_alias_slug_format",
24
+ "aliases",
25
+ "slug ~ '^[a-z0-9][a-z0-9-]*/[a-z0-9][a-z0-9-]*[a-z0-9]$' OR slug ~ '^[a-z0-9][a-z0-9-]*[a-z0-9]$'",
26
+ )
27
+
28
+
29
+ def downgrade() -> None:
30
+ op.drop_constraint("ck_alias_slug_format", "aliases", type_="check")
31
+ op.create_check_constraint(
32
+ "ck_alias_slug_format",
33
+ "aliases",
34
+ "slug ~ '^[a-z0-9][a-z0-9-]*[a-z0-9]$'",
35
+ )
36
+ op.alter_column("aliases", "slug", type_=sa.String(50))
37
+ op.drop_column("programs", "hf_url")
@@ -51,6 +51,7 @@ class Program(Base):
51
51
  tags: Mapped[list[str] | None] = mapped_column(ARRAY(Text), nullable=True)
52
52
  adapter_path: Mapped[str | None] = mapped_column(Text, nullable=True)
53
53
  paw_path: Mapped[str | None] = mapped_column(Text, nullable=True)
54
+ hf_url: Mapped[str | None] = mapped_column(Text, nullable=True)
54
55
  downloads: Mapped[int] = mapped_column(Integer, default=0)
55
56
  upvotes: Mapped[int] = mapped_column(Integer, default=0)
56
57
  downvotes: Mapped[int] = mapped_column(Integer, default=0)
@@ -72,7 +73,7 @@ class Program(Base):
72
73
  class Alias(Base):
73
74
  __tablename__ = "aliases"
74
75
 
75
- slug: Mapped[str] = mapped_column(String(50), primary_key=True)
76
+ slug: Mapped[str] = mapped_column(String(120), primary_key=True)
76
77
  program_id: Mapped[str] = mapped_column(
77
78
  Text, ForeignKey("programs.id"), nullable=False
78
79
  )
@@ -10,7 +10,7 @@ from sqlalchemy import select
10
10
  from sqlalchemy.ext.asyncio import AsyncSession
11
11
 
12
12
  from api.dependencies import get_current_user
13
- from api.models.database import get_db
13
+ from api.models.database import get_db, get_session_factory
14
14
  from api.models.orm import CompileLog, Program, User
15
15
  from api.models.schemas import CompileRequest, CompileResponse, CompileStatusResponse, CompileTimings
16
16
 
@@ -81,9 +81,9 @@ async def submit_compile(
81
81
  "error": None,
82
82
  }
83
83
 
84
- # For now, run compilation synchronously (will switch to Celery for async)
85
84
  import asyncio
86
85
  from api.services.compile_service import SpecTooLongError, get_compile_service
86
+ from api.services.storage_service import upload_paw_to_hf, delete_lora_params
87
87
 
88
88
  try:
89
89
  service = get_compile_service()
@@ -119,6 +119,29 @@ async def submit_compile(
119
119
  ))
120
120
  await db.commit()
121
121
 
122
+ # Background: upload .paw to HF + delete lora_params.pt
123
+ paw_path = result.get("paw_path")
124
+
125
+ async def _background_hf_upload():
126
+ try:
127
+ from pathlib import Path
128
+ if paw_path and Path(paw_path).exists():
129
+ hf_url = await asyncio.to_thread(upload_paw_to_hf, pid, paw_path)
130
+ async with get_session_factory()() as bg_db:
131
+ prog = await bg_db.get(Program, pid)
132
+ if prog:
133
+ prog.hf_url = hf_url
134
+ await bg_db.commit()
135
+
136
+ adapter_dir = Path(paw_path).parent if paw_path else None
137
+ if adapter_dir and adapter_dir.exists():
138
+ delete_lora_params(adapter_dir)
139
+ except Exception:
140
+ logger.exception("background_hf_upload_failed", program_id=pid)
141
+
142
+ if not result.get("cached"):
143
+ asyncio.create_task(_background_hf_upload())
144
+
122
145
  t = result.get("timings", {})
123
146
  def _ms(key: str) -> float | None:
124
147
  v = t.get(key)
@@ -6,7 +6,7 @@ import re
6
6
  from pathlib import Path
7
7
 
8
8
  from fastapi import APIRouter, Depends, HTTPException, Request
9
- from fastapi.responses import FileResponse
9
+ from fastapi.responses import FileResponse, RedirectResponse
10
10
  from sqlalchemy import func, select, or_
11
11
  from sqlalchemy.ext.asyncio import AsyncSession
12
12
 
@@ -14,23 +14,38 @@ from api.config import get_settings
14
14
  from api.dependencies import get_current_user, require_user
15
15
  from api.models.database import get_db
16
16
  from api.models.orm import Alias, Case, Program, User, Vote
17
+ from api.services.storage_service import get_hf_url
17
18
 
18
19
  router = APIRouter()
19
20
 
20
- SLUG_RE = re.compile(r"^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$")
21
+ SLUG_PART_RE = re.compile(r"^[a-z0-9][a-z0-9-]{0,48}[a-z0-9]$")
22
+ SYSTEM_NAMESPACE = "programasweights"
21
23
 
22
24
 
23
25
  async def resolve_program(id_or_slug: str, db: AsyncSession) -> Program | None:
24
- """Resolve a program by hash ID or alias slug."""
26
+ """Resolve a program by hash ID or alias slug.
27
+ Bare slugs (no /) are tried as programasweights/slug first."""
25
28
  result = await db.execute(select(Program).where(Program.id == id_or_slug))
26
29
  program = result.scalar_one_or_none()
27
30
  if program:
28
31
  return program
29
32
 
33
+ slug = id_or_slug
30
34
  result = await db.execute(
31
- select(Program).join(Alias).where(Alias.slug == id_or_slug)
35
+ select(Program).join(Alias).where(Alias.slug == slug)
32
36
  )
33
- return result.scalar_one_or_none()
37
+ program = result.scalar_one_or_none()
38
+ if program:
39
+ return program
40
+
41
+ if "/" not in slug:
42
+ full_slug = f"{SYSTEM_NAMESPACE}/{slug}"
43
+ result = await db.execute(
44
+ select(Program).join(Alias).where(Alias.slug == full_slug)
45
+ )
46
+ return result.scalar_one_or_none()
47
+
48
+ return None
34
49
 
35
50
 
36
51
  # --- Programs CRUD ---
@@ -95,10 +110,16 @@ async def list_programs(
95
110
  }
96
111
 
97
112
 
98
- @router.get("/programs/resolve/{slug}")
113
+ @router.get("/programs/resolve/{slug:path}")
99
114
  async def resolve_slug(slug: str, db: AsyncSession = Depends(get_db)):
100
115
  result = await db.execute(select(Alias).where(Alias.slug == slug))
101
116
  alias = result.scalar_one_or_none()
117
+
118
+ if not alias and "/" not in slug:
119
+ full_slug = f"{SYSTEM_NAMESPACE}/{slug}"
120
+ result = await db.execute(select(Alias).where(Alias.slug == full_slug))
121
+ alias = result.scalar_one_or_none()
122
+
102
123
  if not alias:
103
124
  raise HTTPException(status_code=404, detail={
104
125
  "error": "alias_not_found",
@@ -134,6 +155,7 @@ async def get_program(id_or_slug: str, db: AsyncSession = Depends(get_db)):
134
155
  "public": program.public,
135
156
  "aliases": aliases,
136
157
  "download_url": f"/api/v1/programs/{program.id}/download",
158
+ "hf_url": program.hf_url,
137
159
  "created_at": program.created_at.isoformat() if program.created_at else None,
138
160
  }
139
161
 
@@ -142,29 +164,25 @@ async def get_program(id_or_slug: str, db: AsyncSession = Depends(get_db)):
142
164
  async def download_program(id_or_slug: str, db: AsyncSession = Depends(get_db)):
143
165
  program = await resolve_program(id_or_slug, db)
144
166
  if not program:
145
- settings = get_settings()
146
- paw_file = Path(settings.STORAGE_PATH) / id_or_slug / f"{id_or_slug}.paw"
147
- if paw_file.exists():
148
- return FileResponse(
149
- path=str(paw_file),
150
- media_type="application/octet-stream",
151
- filename=f"{id_or_slug}.paw",
152
- )
153
167
  raise HTTPException(status_code=404, detail=f"Program '{id_or_slug}' not found")
154
168
 
155
169
  program.downloads = (program.downloads or 0) + 1
156
170
  await db.commit()
157
171
 
172
+ if program.hf_url:
173
+ return RedirectResponse(url=program.hf_url, status_code=302)
174
+
158
175
  settings = get_settings()
159
176
  paw_file = Path(settings.STORAGE_PATH) / program.id / f"{program.id}.paw"
160
- if not paw_file.exists():
161
- raise HTTPException(status_code=404, detail=f".paw file not found for '{program.id}'")
177
+ if paw_file.exists():
178
+ return FileResponse(
179
+ path=str(paw_file),
180
+ media_type="application/octet-stream",
181
+ filename=f"{program.id}.paw",
182
+ )
162
183
 
163
- return FileResponse(
164
- path=str(paw_file),
165
- media_type="application/octet-stream",
166
- filename=f"{program.id}.paw",
167
- )
184
+ hf_url = get_hf_url(program.id)
185
+ return RedirectResponse(url=hf_url, status_code=302)
168
186
 
169
187
 
170
188
  # --- Voting ---
@@ -314,26 +332,29 @@ async def create_alias(
314
332
  raise HTTPException(status_code=404, detail="Program not found")
315
333
 
316
334
  body = await request.json()
317
- slug = body.get("slug", "").lower().strip()
335
+ raw_slug = body.get("slug", "").lower().strip()
318
336
 
319
- if not SLUG_RE.match(slug):
337
+ if not SLUG_PART_RE.match(raw_slug):
320
338
  raise HTTPException(status_code=422, detail={
321
339
  "error": "invalid_slug",
322
- "message": "Slug must be 3-50 chars, lowercase alphanumeric and hyphens, "
340
+ "message": "Name must be 2-50 chars, lowercase alphanumeric and hyphens, "
323
341
  "start and end with alphanumeric.",
324
342
  })
325
343
 
326
- existing = await db.execute(select(Alias).where(Alias.slug == slug))
344
+ username = user.username or f"user-{user.id}"
345
+ full_slug = f"{username}/{raw_slug}"
346
+
347
+ existing = await db.execute(select(Alias).where(Alias.slug == full_slug))
327
348
  if existing.scalar_one_or_none():
328
349
  raise HTTPException(status_code=409, detail={
329
350
  "error": "slug_taken",
330
- "message": f"The name '{slug}' is already taken.",
351
+ "message": f"You already have a program named '{raw_slug}'.",
331
352
  })
332
353
 
333
- alias = Alias(slug=slug, program_id=program_id, owner_id=user.id)
354
+ alias = Alias(slug=full_slug, program_id=program_id, owner_id=user.id)
334
355
  db.add(alias)
335
356
  await db.commit()
336
- return {"slug": slug, "program_id": program_id}
357
+ return {"slug": full_slug, "program_id": program_id}
337
358
 
338
359
 
339
360
  @router.delete("/programs/{program_id}/alias/{slug}")
@@ -0,0 +1,114 @@
1
+ """
2
+ Storage service: upload .paw files to HuggingFace, manage local cleanup.
3
+ """
4
+
5
+ import os
6
+ import time
7
+ from pathlib import Path
8
+
9
+ import structlog
10
+
11
+ logger = structlog.get_logger()
12
+
13
+ HF_REPO_ID = "yuntian-deng/paw-programs"
14
+ HF_BASE_URL = f"https://huggingface.co/{HF_REPO_ID}/resolve/main"
15
+
16
+
17
+ def get_hf_url(program_id: str) -> str:
18
+ return f"{HF_BASE_URL}/{program_id}.paw"
19
+
20
+
21
+ def upload_paw_to_hf(program_id: str, paw_path: str) -> str:
22
+ """Upload a .paw file to HuggingFace. Returns the download URL."""
23
+ from huggingface_hub import HfApi
24
+
25
+ api = HfApi()
26
+ url = get_hf_url(program_id)
27
+
28
+ try:
29
+ api.upload_file(
30
+ path_or_fileobj=paw_path,
31
+ path_in_repo=f"{program_id}.paw",
32
+ repo_id=HF_REPO_ID,
33
+ repo_type="model",
34
+ )
35
+ logger.info("hf_upload_success", program_id=program_id, url=url)
36
+ except Exception:
37
+ logger.exception("hf_upload_failed", program_id=program_id)
38
+ raise
39
+
40
+ return url
41
+
42
+
43
+ def delete_lora_params(program_dir: Path) -> int:
44
+ """Delete lora_params.pt if it exists. Returns bytes freed."""
45
+ pt_file = program_dir / "lora_params.pt"
46
+ if pt_file.exists():
47
+ size = pt_file.stat().st_size
48
+ pt_file.unlink()
49
+ logger.info("deleted_lora_params", dir=str(program_dir), freed_mb=round(size / 1024 / 1024, 1))
50
+ return size
51
+ return 0
52
+
53
+
54
+ def cleanup_cold_programs(
55
+ storage_path: Path,
56
+ max_age_days: int = 30,
57
+ keep_peft: bool = True,
58
+ ) -> dict:
59
+ """Remove local files for programs that have HF backups and haven't been accessed recently.
60
+
61
+ Args:
62
+ storage_path: Path to /data/programs
63
+ max_age_days: Programs not accessed in this many days are eligible
64
+ keep_peft: If True, keep adapter_model.safetensors for vLLM inference
65
+ """
66
+ from api.models.database import get_session_factory
67
+ from api.models.orm import Program
68
+ from sqlalchemy import select
69
+ import asyncio
70
+
71
+ cutoff = time.time() - max_age_days * 86400
72
+ stats = {"checked": 0, "cleaned": 0, "bytes_freed": 0, "skipped_no_hf": 0}
73
+
74
+ async def _cleanup():
75
+ factory = get_session_factory()
76
+ async with factory() as db:
77
+ result = await db.execute(
78
+ select(Program).where(Program.hf_url.isnot(None))
79
+ )
80
+ programs = result.scalars().all()
81
+
82
+ for prog in programs:
83
+ stats["checked"] += 1
84
+ prog_dir = storage_path / prog.id
85
+
86
+ if not prog_dir.exists():
87
+ continue
88
+
89
+ paw_file = prog_dir / f"{prog.id}.paw"
90
+ if not paw_file.exists():
91
+ continue
92
+
93
+ last_access = paw_file.stat().st_atime
94
+ if last_access > cutoff:
95
+ continue
96
+
97
+ for fname in ["lora_params.pt", f"{prog.id}.paw", "adapter.gguf"]:
98
+ f = prog_dir / fname
99
+ if f.exists():
100
+ stats["bytes_freed"] += f.stat().st_size
101
+ f.unlink()
102
+
103
+ if not keep_peft:
104
+ for fname in ["adapter_model.safetensors"]:
105
+ f = prog_dir / fname
106
+ if f.exists():
107
+ stats["bytes_freed"] += f.stat().st_size
108
+ f.unlink()
109
+
110
+ stats["cleaned"] += 1
111
+ logger.info("cleaned_program", program_id=prog.id)
112
+
113
+ asyncio.run(_cleanup())
114
+ return stats
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Cleanup script: delete lora_params.pt from all programs, optionally
4
+ clean cold programs that have HF backups.
5
+
6
+ Usage:
7
+ # Delete all lora_params.pt (always safe)
8
+ python scripts/cleanup_storage.py --delete-pt
9
+
10
+ # Clean cold programs (30+ days, have HF backup)
11
+ python scripts/cleanup_storage.py --clean-cold --max-age-days 30
12
+
13
+ # Both
14
+ python scripts/cleanup_storage.py --delete-pt --clean-cold
15
+ """
16
+
17
+ import argparse
18
+ import sys
19
+ from pathlib import Path
20
+
21
+ sys.path.insert(0, str(Path(__file__).parent.parent))
22
+
23
+
24
+ def delete_all_lora_params(storage_path: Path):
25
+ """Delete lora_params.pt from all program directories."""
26
+ total_freed = 0
27
+ count = 0
28
+ for d in storage_path.iterdir():
29
+ if not d.is_dir():
30
+ continue
31
+ pt_file = d / "lora_params.pt"
32
+ if pt_file.exists():
33
+ size = pt_file.stat().st_size
34
+ pt_file.unlink()
35
+ total_freed += size
36
+ count += 1
37
+ print(f"Deleted {count} lora_params.pt files, freed {total_freed / 1024 / 1024:.0f} MB")
38
+
39
+
40
+ def main():
41
+ parser = argparse.ArgumentParser(description="PAW storage cleanup")
42
+ parser.add_argument("--storage-path", default="/data/programs")
43
+ parser.add_argument("--delete-pt", action="store_true",
44
+ help="Delete all lora_params.pt files (always safe)")
45
+ parser.add_argument("--clean-cold", action="store_true",
46
+ help="Clean cold programs with HF backups")
47
+ parser.add_argument("--max-age-days", type=int, default=30)
48
+ args = parser.parse_args()
49
+
50
+ storage = Path(args.storage_path)
51
+ if not storage.exists():
52
+ print(f"Storage path {storage} does not exist")
53
+ return
54
+
55
+ if args.delete_pt:
56
+ delete_all_lora_params(storage)
57
+
58
+ if args.clean_cold:
59
+ from api.services.storage_service import cleanup_cold_programs
60
+ stats = cleanup_cold_programs(storage, max_age_days=args.max_age_days)
61
+ print(f"Cleanup: checked={stats['checked']}, cleaned={stats['cleaned']}, "
62
+ f"freed={stats['bytes_freed'] / 1024 / 1024:.0f} MB")
63
+
64
+
65
+ if __name__ == "__main__":
66
+ main()
@@ -0,0 +1,134 @@
1
+ """
2
+ Tests for the storage + alias + HF upload system.
3
+ TDD: these tests define the expected behavior BEFORE implementation.
4
+ """
5
+
6
+ import pytest
7
+
8
+ # ── Alias resolution ──
9
+
10
+ class TestAliasResolution:
11
+ """Namespaced aliases: username/slug format with programasweights/ shorthand."""
12
+
13
+ async def test_bare_name_resolves_to_programasweights_namespace(self, client):
14
+ """'email-triage' should resolve to programasweights/email-triage."""
15
+ resp = await client.get("/api/v1/programs/resolve/email-triage")
16
+ assert resp.status_code == 200
17
+ data = resp.json()
18
+ assert "program_id" in data
19
+ assert data["slug"] == "programasweights/email-triage"
20
+
21
+ async def test_namespaced_slug_resolves(self, client):
22
+ """'da03/my-program' should resolve to the correct program."""
23
+ resp = await client.get("/api/v1/programs/resolve/da03/my-program")
24
+ assert resp.status_code == 200
25
+ data = resp.json()
26
+ assert "program_id" in data
27
+
28
+ async def test_unknown_slug_returns_404(self, client):
29
+ resp = await client.get("/api/v1/programs/resolve/nonexistent/nope")
30
+ assert resp.status_code == 404
31
+
32
+ async def test_create_alias_requires_auth(self, client):
33
+ resp = await client.post(
34
+ "/api/v1/programs/some_program_id/alias",
35
+ json={"slug": "my-cool-program"},
36
+ )
37
+ assert resp.status_code == 401
38
+
39
+ async def test_create_alias_adds_username_prefix(self, client, auth_headers):
40
+ """Creating alias 'my-prog' as user 'da03' should store 'da03/my-prog'."""
41
+ resp = await client.post(
42
+ "/api/v1/programs/some_program_id/alias",
43
+ json={"slug": "my-prog"},
44
+ headers=auth_headers,
45
+ )
46
+ assert resp.status_code in (200, 201)
47
+ data = resp.json()
48
+ assert data["slug"] == "da03/my-prog"
49
+
50
+ async def test_duplicate_slug_returns_409(self, client, auth_headers):
51
+ """Same user can't create the same alias twice."""
52
+ await client.post(
53
+ "/api/v1/programs/some_program_id/alias",
54
+ json={"slug": "unique-name"},
55
+ headers=auth_headers,
56
+ )
57
+ resp = await client.post(
58
+ "/api/v1/programs/some_program_id/alias",
59
+ json={"slug": "unique-name"},
60
+ headers=auth_headers,
61
+ )
62
+ assert resp.status_code == 409
63
+
64
+
65
+ # ── Download redirect ──
66
+
67
+ class TestDownloadRedirect:
68
+ """Download endpoint should redirect to HuggingFace URL."""
69
+
70
+ async def test_download_redirects_to_hf(self, client):
71
+ """GET /programs/{id}/download should return 302 to HF URL."""
72
+ resp = await client.get(
73
+ "/api/v1/programs/9b57fd6fccf77885400e/download",
74
+ follow_redirects=False,
75
+ )
76
+ assert resp.status_code in (302, 307)
77
+ location = resp.headers.get("location", "")
78
+ assert "huggingface.co" in location
79
+ assert "9b57fd6fccf77885400e" in location
80
+
81
+ async def test_download_by_slug_redirects(self, client):
82
+ """GET /programs/email-triage/download should also redirect."""
83
+ resp = await client.get(
84
+ "/api/v1/programs/email-triage/download",
85
+ follow_redirects=False,
86
+ )
87
+ assert resp.status_code in (302, 307)
88
+
89
+ async def test_download_unknown_returns_404(self, client):
90
+ resp = await client.get("/api/v1/programs/nonexistent_id/download")
91
+ assert resp.status_code == 404
92
+
93
+
94
+ # ── HF upload ──
95
+
96
+ class TestHFUpload:
97
+ """After compile, .paw should be uploaded to HuggingFace."""
98
+
99
+ async def test_compile_sets_hf_url(self, client, auth_headers):
100
+ """After successful compile, program should have hf_url set in DB."""
101
+ resp = await client.post(
102
+ "/api/v1/compile",
103
+ json={"spec": "Classify text as spam or not spam"},
104
+ headers=auth_headers,
105
+ )
106
+ if resp.status_code == 202:
107
+ data = resp.json()
108
+ if data["status"] == "ready":
109
+ program_id = data["program_id"]
110
+ prog_resp = await client.get(f"/api/v1/programs/{program_id}")
111
+ prog_data = prog_resp.json()
112
+ assert prog_data.get("hf_url") is not None
113
+ assert "huggingface.co" in prog_data["hf_url"]
114
+
115
+
116
+ # ── Cleanup ──
117
+
118
+ class TestCleanup:
119
+ """Cleanup should remove local files for cold programs that have HF backups."""
120
+
121
+ def test_lora_params_never_needed(self):
122
+ """lora_params.pt should never exist after compile+cleanup."""
123
+ import os
124
+ from pathlib import Path
125
+ programs_dir = Path("/data/programs")
126
+ if programs_dir.exists():
127
+ for d in programs_dir.iterdir():
128
+ pt_file = d / "lora_params.pt"
129
+ if pt_file.exists():
130
+ size_mb = pt_file.stat().st_size / 1024 / 1024
131
+ pytest.fail(
132
+ f"lora_params.pt still exists in {d.name} ({size_mb:.0f} MB). "
133
+ "Should be deleted after GGUF conversion."
134
+ )