programasweights 0.1.0.dev1__tar.gz → 0.1.0.dev2__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.
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/PKG-INFO +1 -1
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights/__init__.py +1 -1
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights/cache.py +3 -5
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/pyproject.toml +1 -1
- programasweights-0.1.0.dev2/web-app/frontend/src/components/CasesSection.tsx +180 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/Header.tsx +31 -87
- programasweights-0.1.0.dev2/web-app/frontend/src/components/HubPage.tsx +180 -0
- programasweights-0.1.0.dev2/web-app/frontend/src/components/HubProgramPage.tsx +237 -0
- programasweights-0.1.0.dev2/web-app/frontend/src/components/HubUploadPage.tsx +14 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/LandingPage.tsx +18 -38
- programasweights-0.1.0.dev2/web-app/frontend/src/components/MainInterface.tsx +381 -0
- programasweights-0.1.0.dev2/web-app/frontend/src/components/ProfilePage.tsx +102 -0
- programasweights-0.1.0.dev2/web-app/frontend/src/types/index.ts +192 -0
- programasweights-0.1.0.dev2/web-app/frontend/src/utils/api.ts +164 -0
- programasweights-0.1.0.dev1/web-app/frontend/src/components/CasesSection.tsx +0 -406
- programasweights-0.1.0.dev1/web-app/frontend/src/components/HubPage.tsx +0 -293
- programasweights-0.1.0.dev1/web-app/frontend/src/components/HubProgramPage.tsx +0 -389
- programasweights-0.1.0.dev1/web-app/frontend/src/components/HubUploadPage.tsx +0 -222
- programasweights-0.1.0.dev1/web-app/frontend/src/components/MainInterface.tsx +0 -568
- programasweights-0.1.0.dev1/web-app/frontend/src/components/ProfilePage.tsx +0 -272
- programasweights-0.1.0.dev1/web-app/frontend/src/types/index.ts +0 -182
- programasweights-0.1.0.dev1/web-app/frontend/src/utils/api.ts +0 -84
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/.gitignore +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/.hatch_build.toml +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/.readthedocs.yaml +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/1apple.jpg +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/1apple2.jpg +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/2apples.jpg +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/2apples2.jpg +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/3apples.jpg +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/3apples2.jpg +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/479400.png +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/4apples.jpg +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/4apples2.jpg +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/4apples3.jpg +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/4apples4.jpg +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/5apples.jpg +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/6apples.jpg +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/8apples.jpg +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/9apples.jpg +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/FLOW_SUMMARY.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/MANIFEST.in +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/ONNX_MIGRATION_PLAN.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/PREFIX_TOKENS_DESIGN.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/PYPI_README.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/README.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/TRUNCATION_CHANGES.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/VERIFICATION_USAGE.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/analyze_dataset.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/analyze_lengths.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/baselines/code_prompt.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/baselines/evaluate_openai_python_code_baseline.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/baselines/openai_batch_request.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/baselines/prepare_alchemist_data.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/baselines/prepare_var_bench_data.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/baselines/python_code_sandbox.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/baselines/script_evaluation_var_bench.sh +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/baselines/script_evalution_evaluation.sh +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/baselines/script_evalution_request.sh +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/baselines/script_evalution_statistics.sh +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/benchmark_pytorch_vs_onnx.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/benchmark_user_experience.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/check_dataset.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/combine_datasets.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/compare_datasets.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/compare_old_vs_regen.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/convert_paw_to_svg.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/create_favicon_sizes.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/create_visualization_from_log.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/create_vqa_dataset.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/debug_cache.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/debug_eos_example.sh +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/docs/Makefile +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/docs/adr/001-llama-cpp-over-pytorch.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/docs/adr/002-q4_0-adapter-format.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/docs/adr/003-single-spec-field.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/docs/adr/004-compiler-naming.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/docs/adr/005-vllm-hidden-states.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/docs/adr/006-email-api-key-auth.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/docs/api-reference.rst +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/docs/architecture.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/docs/conf.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/docs/examples/evaluation-tasks.rst +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/docs/index.rst +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/docs/installation.rst +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/docs/make.bat +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/docs/quickstart.rst +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/docs/requirements.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/docs/using-pretrained.rst +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/estimate_data_gen_cost.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/eval.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/examples/flask_app.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/examples/jupyter_notebook.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/examples/langchain_integration.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/examples/replace_openai.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/export_to_onnx.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/extract_models.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/inspect_data_dirs.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/latest_export.csv +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/log.train.81920.morecategories.extraprefix +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/main_no_spec_direct_ans_mix_continuous_sampleref_shorterprompt_vllm.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/merge_datasets.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/paw.png +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/paw.svg +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/process_im2latex_dataset.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights/artifacts.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights/cli.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights/client.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights/compiler/__init__.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights/compiler/dummy.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights/config.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights/convert_peft_to_paw.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights/paw_format.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights/runtime/__init__.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights/runtime/interpreter.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights/runtime/interpreter_onnx.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights/runtime_llamacpp.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights_lora/__init__.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights_lora/compiler/__init__.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights_lora/lora_format.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights_lora/runtime/__init__.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights_lora/runtime/interpreter_lora.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights_lora/tests/test_compile_and_run.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights_lora/tests/test_lora_format.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights_lora/tests/test_training.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights_lora/train_lora.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights_lora/training/__init__.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/programasweights_lora/training/loops/lora_tuning_sft.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/run_eval.sh +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/run_training.sh +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/scripts/filter_table_by_length.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/.env.example +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/api/__init__.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/api/config.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/api/logging_config.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/api/main.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/api/models/__init__.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/api/models/schemas.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/api/routes/__init__.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/api/routes/auth.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/api/routes/compile.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/api/routes/health.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/api/routes/infer.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/api/routes/models_info.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/api/routes/programs.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/api/services/__init__.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/api/services/compile_service.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/api/services/infer_service.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/benchmarks/benchmark_api.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/benchmarks/handcrafted_specs.json +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/benchmarks/last_benchmark_results.json +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/benchmarks/last_stress_results.json +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/benchmarks/stress_test.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/requirements.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/scripts/start_services.sh +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/tests/__init__.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/tests/conftest.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/tests/test_auth.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/tests/test_compile.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/tests/test_errors.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/tests/test_infer.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/tests/test_integration_gpu.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/tests/test_rate_limit.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/vllm_models/__init__.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/vllm_models/paw_compiler.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/vllm_models/prepare_checkpoint.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/server/vllm_models/register.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/stage2_firstpromptqwen_512_e1_generate_lora_e2grpo_overfit_one_debug.reward_plot.rollout_ppl.png +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/stage2_firstpromptqwen_512_e1_generate_lora_e2grpo_overfit_one_debug.reward_plot.train_gt_logprob.em_es.png +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/stage2_firstpromptqwen_512_e1_generate_lora_e2grpo_overfit_one_debug.reward_plot.train_gt_logprob.ppl.png +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/stage2_firstpromptqwen_512_e1_generate_lora_e2grpo_overfit_one_debug.reward_plot.train_gt_logprob.reward.png +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/test_1spec.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/test_all_caching.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/test_apple_count.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/test_batch_pilot.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/test_compile.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/test_e2e.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/test_execute.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/test_nspecs.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/test_one_vs_two_step.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/test_onnx_correctness.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/test_onnx_hf_model.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/test_onnx_hf_with_images.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/test_paw_format.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/test_thinking_comparison.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/tests/test_programasweights.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/train.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/train_no_spec_direct_ans_mix_continuous_sampleref_trainonly_shorterprompt_withregularizer_generate_lora.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/README.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/__init__.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/DATASET_CHANGELOG.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/README.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/VERIFICATION_PIPELINE.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/dry_run_batch.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/filter_test_data.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/generate_specs.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/generate_specs_batch.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/incremental_merge.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/merge_and_upload.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/regenerate_outputs_batch.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/synthesize_data.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/synthesize_data_batch.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates/filter_system.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates/filter_user.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates/pairs_system.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates/pairs_user.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates/specs_system.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates/specs_user.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates/specs_user_freeform.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates/specs_user_freeform_with_examples.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates/specs_user_with_examples.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates/verify_system.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates/verify_user.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates_old/filter_system.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates_old/filter_user.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates_old/pairs_system.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates_old/pairs_user.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates_old/specs_system.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates_old/specs_user.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates_old/specs_user_freeform.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates_old/specs_user_freeform_with_examples.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates_old/specs_user_with_examples.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates_old/verify_system.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/templates_old/verify_user.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/data_generation/verify_test_data.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/datasets/__init__.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/datasets/jsonl_text_pairs.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/loops/__init__.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/training/loops/prefix_tuning_sft.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/ttt.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/upload_model.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/upload_onnx_to_huggingface.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/upload_onnx_to_huggingface_with_token.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/utils.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/HANDOFF.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/README.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/app/__init__.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/app/config.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/app/main.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/app/middleware/__init__.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/app/middleware/rate_limit.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/app/models.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/app/services/__init__.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/app/services/auth_service.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/app/services/case_service.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/app/services/compiler_service.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/app/services/gpt_service.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/app/services/hub_service.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/app/services/image_service.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/app/services/interpreter_service.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/app/services/sql_manager.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/app/templates/gpt_test_generation.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/app/utils/__init__.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/app/utils/image_placeholders.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/app/utils/program_hash.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/clear_db.sh +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/clear_tables.sql +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/data/programs.db +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/env_example.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/example_images/README.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/get_data_examples.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/requirements.txt +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/run_server.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/setup_analytics_tables.sql +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/setup_auth_tables.sql +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/setup_cache_tables.sql +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/setup_cases_tables.sql +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/setup_database.sql +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/setup_database_simple.sql +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/setup_db.sh +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/setup_example_images.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/setup_hub_tables.sql +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/backend/test_compilation_cache.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/README.md +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/eslint.config.js +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/index.html +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/package-lock.json +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/package.json +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/postcss.config.js +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/public/apple-touch-icon.png +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/public/favicon-16x16.png +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/public/favicon-32x32.png +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/public/paw-192.png +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/public/paw-512.png +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/public/paw.svg +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/public/react-test.html +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/public/test.html +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/public/vite.svg +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/App.css +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/App.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/assets/react.svg +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/AboutPage.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/AutoTestSection.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/CollapsibleExamples.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/CompileButtonWithConfig.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/CompileSection.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/CopyCodeSection.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/DocsPage.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/ExampleRow/ExampleRowEditor.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/ExamplesInput.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/Footer.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/ImageUpload.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/InputBlocks/ImageBlock.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/InputBlocks/InputBlockList.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/InputBlocks/TextBlock.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/LeaderboardPage.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/ModelSelector.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/MultiImageUpload.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/PricingPage.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/PrivacyPage.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/ProgramDetailPage.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/PublishProgramPage.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/SpecInput.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/TermsPage.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/components/TestSection.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/index.css +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/src/main.tsx +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/tailwind.config.js +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/tsconfig.app.json +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/tsconfig.json +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/tsconfig.node.json +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/frontend/vite.config.ts +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/nginx-paw.conf +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/nginx.conf +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/setup_mysql.sh +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/start.sh +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/web-app/test_setup.py +0 -0
- {programasweights-0.1.0.dev1 → programasweights-0.1.0.dev2}/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.
|
|
3
|
+
Version: 0.1.0.dev2
|
|
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
|
|
@@ -21,14 +21,12 @@ import httpx
|
|
|
21
21
|
|
|
22
22
|
from . import config
|
|
23
23
|
|
|
24
|
-
# Known base model GGUF files (interpreter models)
|
|
25
24
|
BASE_MODEL_URLS = {
|
|
26
|
-
"qwen3-0.6b-
|
|
25
|
+
"qwen3-0.6b-q6_k": "https://programasweights.com/models/qwen3-0.6b-q6_k.gguf",
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
# Map interpreter model names to GGUF filenames
|
|
30
28
|
INTERPRETER_TO_GGUF = {
|
|
31
|
-
"Qwen/Qwen3-0.6B": "qwen3-0.6b-
|
|
29
|
+
"Qwen/Qwen3-0.6B": "qwen3-0.6b-q6_k",
|
|
32
30
|
}
|
|
33
31
|
|
|
34
32
|
|
|
@@ -47,7 +45,7 @@ def get_base_model_path(interpreter: str = "Qwen/Qwen3-0.6B") -> Path:
|
|
|
47
45
|
f"Available: {list(INTERPRETER_TO_GGUF.keys())}"
|
|
48
46
|
)
|
|
49
47
|
|
|
50
|
-
print(f"Downloading base model {gguf_name} (
|
|
48
|
+
print(f"Downloading base model {gguf_name} (one-time download)...")
|
|
51
49
|
_download_file(url, gguf_path)
|
|
52
50
|
print(f"Saved to {gguf_path}")
|
|
53
51
|
return gguf_path
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "programasweights"
|
|
7
|
-
version = "0.1.0.
|
|
7
|
+
version = "0.1.0.dev2"
|
|
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,180 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import { ThumbsUp, ThumbsDown, Trash2, Plus, Send } from 'lucide-react';
|
|
3
|
+
import { apiClient } from '../utils/api';
|
|
4
|
+
import toast from 'react-hot-toast';
|
|
5
|
+
import type { ProgramCase, CaseType, CaseCounts } from '../types';
|
|
6
|
+
|
|
7
|
+
interface CasesSectionProps {
|
|
8
|
+
programId: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const CasesSection: React.FC<CasesSectionProps> = ({ programId }) => {
|
|
12
|
+
const [cases, setCases] = useState<ProgramCase[]>([]);
|
|
13
|
+
const [counts, setCounts] = useState<CaseCounts>({ success: 0, limitation: 0, edge_case: 0 });
|
|
14
|
+
const [selectedType, setSelectedType] = useState<CaseType | undefined>(undefined);
|
|
15
|
+
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
|
16
|
+
const [showForm, setShowForm] = useState(false);
|
|
17
|
+
const [newCase, setNewCase] = useState({ input_text: '', output_text: '', case_type: 'success' as CaseType, description: '' });
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
apiClient.getAuthUser().then(r => { if (r.authenticated) setIsAuthenticated(true); }).catch(() => {});
|
|
21
|
+
loadCases();
|
|
22
|
+
}, [programId, selectedType]);
|
|
23
|
+
|
|
24
|
+
const loadCases = async () => {
|
|
25
|
+
try {
|
|
26
|
+
const res = await apiClient.getCases(programId, { case_type: selectedType });
|
|
27
|
+
setCases(res.cases);
|
|
28
|
+
setCounts(res.counts);
|
|
29
|
+
} catch {
|
|
30
|
+
setCases([]);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const handleVote = async (caseItem: ProgramCase, vote: 1 | -1) => {
|
|
35
|
+
const newVote = caseItem.user_vote === vote ? 0 : vote;
|
|
36
|
+
try {
|
|
37
|
+
await apiClient.voteCase(caseItem.id, newVote as 1 | -1 | 0);
|
|
38
|
+
loadCases();
|
|
39
|
+
} catch {
|
|
40
|
+
toast.error('Vote failed');
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const handleDelete = async (caseId: number) => {
|
|
45
|
+
try {
|
|
46
|
+
await apiClient.deleteCase(caseId);
|
|
47
|
+
setCases(prev => prev.filter(c => c.id !== caseId));
|
|
48
|
+
toast.success('Case deleted');
|
|
49
|
+
} catch {
|
|
50
|
+
toast.error('Delete failed');
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const handleSubmit = async () => {
|
|
55
|
+
if (!newCase.input_text.trim() || !newCase.output_text.trim()) {
|
|
56
|
+
toast.error('Please fill in input and output');
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
await apiClient.createCase(programId, newCase);
|
|
61
|
+
setShowForm(false);
|
|
62
|
+
setNewCase({ input_text: '', output_text: '', case_type: 'success', description: '' });
|
|
63
|
+
loadCases();
|
|
64
|
+
toast.success('Case submitted!');
|
|
65
|
+
} catch {
|
|
66
|
+
toast.error('Failed to submit case');
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const typeLabels: Record<CaseType, { label: string; color: string }> = {
|
|
71
|
+
success: { label: 'Successes', color: 'bg-green-100 text-green-700' },
|
|
72
|
+
limitation: { label: 'Limitations', color: 'bg-amber-100 text-amber-700' },
|
|
73
|
+
edge_case: { label: 'Edge Cases', color: 'bg-blue-100 text-blue-700' },
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<div className="bg-white rounded-xl border border-gray-200 p-6">
|
|
78
|
+
<div className="flex items-center justify-between mb-4">
|
|
79
|
+
<h2 className="font-semibold text-gray-900">Community Cases</h2>
|
|
80
|
+
{isAuthenticated && (
|
|
81
|
+
<button onClick={() => setShowForm(!showForm)} className="flex items-center gap-1 text-sm text-blue-600 hover:text-blue-800 font-medium">
|
|
82
|
+
<Plus className="w-3.5 h-3.5" /> Add Case
|
|
83
|
+
</button>
|
|
84
|
+
)}
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
{/* Type filter */}
|
|
88
|
+
<div className="flex gap-2 mb-4">
|
|
89
|
+
<button
|
|
90
|
+
onClick={() => setSelectedType(undefined)}
|
|
91
|
+
className={`px-3 py-1 rounded-full text-xs font-medium ${!selectedType ? 'bg-gray-900 text-white' : 'bg-gray-100 text-gray-600 hover:bg-gray-200'}`}
|
|
92
|
+
>
|
|
93
|
+
All ({counts.success + counts.limitation + counts.edge_case})
|
|
94
|
+
</button>
|
|
95
|
+
{(Object.entries(typeLabels) as [CaseType, { label: string; color: string }][]).map(([type, { label, color }]) => (
|
|
96
|
+
<button
|
|
97
|
+
key={type}
|
|
98
|
+
onClick={() => setSelectedType(selectedType === type ? undefined : type)}
|
|
99
|
+
className={`px-3 py-1 rounded-full text-xs font-medium ${selectedType === type ? color : 'bg-gray-100 text-gray-600 hover:bg-gray-200'}`}
|
|
100
|
+
>
|
|
101
|
+
{label} ({counts[type]})
|
|
102
|
+
</button>
|
|
103
|
+
))}
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
{/* New case form */}
|
|
107
|
+
{showForm && (
|
|
108
|
+
<div className="border border-gray-200 rounded-lg p-4 mb-4 space-y-3">
|
|
109
|
+
<div className="grid grid-cols-2 gap-3">
|
|
110
|
+
<div>
|
|
111
|
+
<label className="text-xs text-gray-500 mb-1 block">Input</label>
|
|
112
|
+
<textarea value={newCase.input_text} onChange={e => setNewCase({ ...newCase, input_text: e.target.value })} rows={2} className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm resize-none" placeholder="Input..." />
|
|
113
|
+
</div>
|
|
114
|
+
<div>
|
|
115
|
+
<label className="text-xs text-gray-500 mb-1 block">Output</label>
|
|
116
|
+
<textarea value={newCase.output_text} onChange={e => setNewCase({ ...newCase, output_text: e.target.value })} rows={2} className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm resize-none" placeholder="Output..." />
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
<div className="flex items-center gap-3">
|
|
120
|
+
<select value={newCase.case_type} onChange={e => setNewCase({ ...newCase, case_type: e.target.value as CaseType })} className="text-sm border border-gray-200 rounded-md px-2 py-1">
|
|
121
|
+
<option value="success">Success</option>
|
|
122
|
+
<option value="limitation">Limitation</option>
|
|
123
|
+
<option value="edge_case">Edge Case</option>
|
|
124
|
+
</select>
|
|
125
|
+
<input value={newCase.description} onChange={e => setNewCase({ ...newCase, description: e.target.value })} className="flex-1 px-3 py-1 border border-gray-200 rounded-lg text-sm" placeholder="Brief description (optional)" />
|
|
126
|
+
<button onClick={handleSubmit} className="flex items-center gap-1 px-4 py-1.5 bg-gray-900 text-white rounded-lg text-sm hover:bg-gray-800">
|
|
127
|
+
<Send className="w-3.5 h-3.5" /> Submit
|
|
128
|
+
</button>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
)}
|
|
132
|
+
|
|
133
|
+
{/* Cases list */}
|
|
134
|
+
{cases.length === 0 ? (
|
|
135
|
+
<p className="text-sm text-gray-400 text-center py-6">No cases yet. Be the first to contribute!</p>
|
|
136
|
+
) : (
|
|
137
|
+
<div className="space-y-3">
|
|
138
|
+
{cases.map(c => (
|
|
139
|
+
<div key={c.id} className="border border-gray-100 rounded-lg p-3">
|
|
140
|
+
<div className="flex items-start justify-between gap-2">
|
|
141
|
+
<div className="flex-1 min-w-0">
|
|
142
|
+
<span className={`inline-block px-2 py-0.5 rounded-full text-[10px] font-medium mb-2 ${typeLabels[c.case_type].color}`}>
|
|
143
|
+
{typeLabels[c.case_type].label.slice(0, -1)}
|
|
144
|
+
</span>
|
|
145
|
+
{c.description && <p className="text-sm text-gray-700 mb-2">{c.description}</p>}
|
|
146
|
+
<div className="grid grid-cols-2 gap-2">
|
|
147
|
+
<div className="bg-gray-50 rounded p-2">
|
|
148
|
+
<p className="text-[10px] text-gray-400 mb-1">Input</p>
|
|
149
|
+
<p className="text-xs font-mono text-gray-700 truncate">{c.input_text}</p>
|
|
150
|
+
</div>
|
|
151
|
+
<div className="bg-gray-50 rounded p-2">
|
|
152
|
+
<p className="text-[10px] text-gray-400 mb-1">Output</p>
|
|
153
|
+
<p className="text-xs font-mono text-gray-700 truncate">{c.output_text}</p>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
<div className="flex flex-col items-center gap-1 text-xs text-gray-400">
|
|
158
|
+
<button onClick={() => handleVote(c, 1)} className={`p-1 rounded ${c.user_vote === 1 ? 'text-green-600' : 'hover:text-green-600'}`}>
|
|
159
|
+
<ThumbsUp className="w-3.5 h-3.5" />
|
|
160
|
+
</button>
|
|
161
|
+
<span>{c.upvotes - c.downvotes}</span>
|
|
162
|
+
<button onClick={() => handleVote(c, -1)} className={`p-1 rounded ${c.user_vote === -1 ? 'text-red-600' : 'hover:text-red-600'}`}>
|
|
163
|
+
<ThumbsDown className="w-3.5 h-3.5" />
|
|
164
|
+
</button>
|
|
165
|
+
{isAuthenticated && (
|
|
166
|
+
<button onClick={() => handleDelete(c.id)} className="p-1 text-gray-300 hover:text-red-500 mt-1">
|
|
167
|
+
<Trash2 className="w-3 h-3" />
|
|
168
|
+
</button>
|
|
169
|
+
)}
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
))}
|
|
174
|
+
</div>
|
|
175
|
+
)}
|
|
176
|
+
</div>
|
|
177
|
+
);
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
export default CasesSection;
|
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
import { useState, useEffect } from 'react';
|
|
2
2
|
import { Link, useLocation } from 'react-router-dom';
|
|
3
|
-
import {
|
|
3
|
+
import { BookOpen, Package, LogOut, Play, Menu, X, DollarSign, Github } from 'lucide-react';
|
|
4
4
|
import { apiClient } from '../utils/api';
|
|
5
|
-
|
|
6
|
-
interface User {
|
|
7
|
-
id: number;
|
|
8
|
-
username: string;
|
|
9
|
-
displayName: string;
|
|
10
|
-
avatarUrl: string;
|
|
11
|
-
}
|
|
5
|
+
import type { AuthUser } from '../types';
|
|
12
6
|
|
|
13
7
|
const Header: React.FC = () => {
|
|
14
8
|
const location = useLocation();
|
|
15
|
-
const [user, setUser] = useState<
|
|
9
|
+
const [user, setUser] = useState<AuthUser | null>(null);
|
|
16
10
|
const [showUserMenu, setShowUserMenu] = useState(false);
|
|
17
11
|
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
|
18
12
|
|
|
@@ -25,39 +19,16 @@ const Header: React.FC = () => {
|
|
|
25
19
|
|
|
26
20
|
const isActive = (path: string) => location.pathname === path;
|
|
27
21
|
|
|
28
|
-
// Check auth status on mount
|
|
29
22
|
useEffect(() => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (response.authenticated && response.user) {
|
|
34
|
-
setUser(response.user);
|
|
35
|
-
}
|
|
36
|
-
} catch {
|
|
37
|
-
// Not logged in - that's fine
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
checkAuth();
|
|
23
|
+
apiClient.getAuthUser()
|
|
24
|
+
.then(res => { if (res.authenticated) setUser(res); })
|
|
25
|
+
.catch(() => {});
|
|
41
26
|
}, []);
|
|
42
27
|
|
|
43
|
-
const handleLogin = async () => {
|
|
44
|
-
try {
|
|
45
|
-
const response = await apiClient.getGithubLoginUrl();
|
|
46
|
-
window.location.href = response.url;
|
|
47
|
-
} catch {
|
|
48
|
-
// Fallback
|
|
49
|
-
window.location.href = '/api/auth/github';
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
|
|
53
28
|
const handleLogout = async () => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
setShowUserMenu(false);
|
|
58
|
-
} catch {
|
|
59
|
-
setUser(null);
|
|
60
|
-
}
|
|
29
|
+
await apiClient.logout();
|
|
30
|
+
setUser(null);
|
|
31
|
+
setShowUserMenu(false);
|
|
61
32
|
};
|
|
62
33
|
|
|
63
34
|
return (
|
|
@@ -73,17 +44,14 @@ const Header: React.FC = () => {
|
|
|
73
44
|
<p className="text-xs text-gray-500 hidden sm:block">ProgramAsWeights</p>
|
|
74
45
|
</div>
|
|
75
46
|
</Link>
|
|
76
|
-
|
|
77
|
-
{/* Desktop nav */}
|
|
47
|
+
|
|
78
48
|
<nav className="hidden md:flex items-center space-x-1">
|
|
79
49
|
{navItems.map(({ path, label, icon: Icon }) => (
|
|
80
50
|
<Link
|
|
81
51
|
key={path}
|
|
82
52
|
to={path}
|
|
83
53
|
className={`flex items-center space-x-2 px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
|
84
|
-
isActive(path)
|
|
85
|
-
? 'bg-gray-100 text-gray-900'
|
|
86
|
-
: 'text-gray-600 hover:text-gray-900 hover:bg-gray-50'
|
|
54
|
+
isActive(path) ? 'bg-gray-100 text-gray-900' : 'text-gray-600 hover:text-gray-900 hover:bg-gray-50'
|
|
87
55
|
}`}
|
|
88
56
|
>
|
|
89
57
|
<Icon className="w-4 h-4" />
|
|
@@ -94,7 +62,7 @@ const Header: React.FC = () => {
|
|
|
94
62
|
|
|
95
63
|
<div className="flex items-center space-x-3">
|
|
96
64
|
<a
|
|
97
|
-
href="https://github.com/
|
|
65
|
+
href="https://github.com/yuntian-group/programasweights"
|
|
98
66
|
target="_blank"
|
|
99
67
|
rel="noopener noreferrer"
|
|
100
68
|
className="hidden md:flex items-center space-x-1.5 text-gray-500 hover:text-gray-900 transition-colors text-sm"
|
|
@@ -103,39 +71,37 @@ const Header: React.FC = () => {
|
|
|
103
71
|
<span className="hidden lg:inline">GitHub</span>
|
|
104
72
|
</a>
|
|
105
73
|
|
|
106
|
-
{user ? (
|
|
74
|
+
{user?.authenticated ? (
|
|
107
75
|
<div className="relative">
|
|
108
76
|
<button
|
|
109
77
|
onClick={() => setShowUserMenu(!showUserMenu)}
|
|
110
78
|
className="flex items-center space-x-2 hover:opacity-80 transition-opacity"
|
|
111
79
|
>
|
|
112
|
-
|
|
113
|
-
src={user.
|
|
114
|
-
|
|
115
|
-
className="w-8 h-8 rounded-full
|
|
116
|
-
|
|
80
|
+
{user.avatar_url ? (
|
|
81
|
+
<img src={user.avatar_url} alt="" className="w-8 h-8 rounded-full border-2 border-gray-200" />
|
|
82
|
+
) : (
|
|
83
|
+
<div className="w-8 h-8 rounded-full bg-gray-300 flex items-center justify-center text-sm font-medium text-gray-600">
|
|
84
|
+
{(user.email || '?')[0].toUpperCase()}
|
|
85
|
+
</div>
|
|
86
|
+
)}
|
|
117
87
|
<span className="text-sm font-medium text-gray-700 hidden lg:inline">
|
|
118
|
-
{user.
|
|
88
|
+
{user.display_name || user.username || user.email}
|
|
119
89
|
</span>
|
|
120
90
|
</button>
|
|
121
|
-
|
|
91
|
+
|
|
122
92
|
{showUserMenu && (
|
|
123
93
|
<div className="absolute right-0 mt-2 w-48 bg-white rounded-lg shadow-lg border border-gray-200 py-1 z-50">
|
|
124
|
-
<div className="px-4 py-2 border-b border-gray-100">
|
|
125
|
-
<p className="text-sm font-medium text-gray-900">{user.displayName}</p>
|
|
126
|
-
<p className="text-xs text-gray-500">@{user.username}</p>
|
|
127
|
-
</div>
|
|
128
94
|
<Link
|
|
129
95
|
to="/profile"
|
|
130
96
|
onClick={() => setShowUserMenu(false)}
|
|
131
|
-
className="w-full flex items-center space-x-2 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50
|
|
97
|
+
className="w-full flex items-center space-x-2 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50"
|
|
132
98
|
>
|
|
133
99
|
<Package className="w-4 h-4" />
|
|
134
100
|
<span>My Programs</span>
|
|
135
101
|
</Link>
|
|
136
102
|
<button
|
|
137
103
|
onClick={handleLogout}
|
|
138
|
-
className="w-full flex items-center space-x-2 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50
|
|
104
|
+
className="w-full flex items-center space-x-2 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50"
|
|
139
105
|
>
|
|
140
106
|
<LogOut className="w-4 h-4" />
|
|
141
107
|
<span>Sign out</span>
|
|
@@ -144,16 +110,15 @@ const Header: React.FC = () => {
|
|
|
144
110
|
)}
|
|
145
111
|
</div>
|
|
146
112
|
) : (
|
|
147
|
-
<
|
|
148
|
-
|
|
113
|
+
<Link
|
|
114
|
+
to="/playground"
|
|
149
115
|
className="hidden sm:flex items-center space-x-2 px-4 py-2 bg-gray-900 text-white rounded-lg hover:bg-gray-800 transition-colors text-sm font-medium"
|
|
150
116
|
>
|
|
151
|
-
<
|
|
152
|
-
<span>
|
|
153
|
-
</
|
|
117
|
+
<Play className="w-4 h-4" />
|
|
118
|
+
<span>Get Started</span>
|
|
119
|
+
</Link>
|
|
154
120
|
)}
|
|
155
121
|
|
|
156
|
-
{/* Mobile menu button */}
|
|
157
122
|
<button
|
|
158
123
|
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
|
159
124
|
className="md:hidden p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded-lg transition-colors"
|
|
@@ -163,9 +128,8 @@ const Header: React.FC = () => {
|
|
|
163
128
|
</div>
|
|
164
129
|
</div>
|
|
165
130
|
|
|
166
|
-
{/* Mobile menu */}
|
|
167
131
|
{mobileMenuOpen && (
|
|
168
|
-
<div className="md:hidden mt-3 pt-3 border-t border-gray-100 pb-2
|
|
132
|
+
<div className="md:hidden mt-3 pt-3 border-t border-gray-100 pb-2">
|
|
169
133
|
<nav className="space-y-1">
|
|
170
134
|
{navItems.map(({ path, label, icon: Icon }) => (
|
|
171
135
|
<Link
|
|
@@ -173,33 +137,13 @@ const Header: React.FC = () => {
|
|
|
173
137
|
to={path}
|
|
174
138
|
onClick={() => setMobileMenuOpen(false)}
|
|
175
139
|
className={`flex items-center space-x-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-colors ${
|
|
176
|
-
isActive(path)
|
|
177
|
-
? 'bg-gray-100 text-gray-900'
|
|
178
|
-
: 'text-gray-600 hover:bg-gray-50'
|
|
140
|
+
isActive(path) ? 'bg-gray-100 text-gray-900' : 'text-gray-600 hover:bg-gray-50'
|
|
179
141
|
}`}
|
|
180
142
|
>
|
|
181
143
|
<Icon className="w-4 h-4" />
|
|
182
144
|
<span>{label}</span>
|
|
183
145
|
</Link>
|
|
184
146
|
))}
|
|
185
|
-
<a
|
|
186
|
-
href="https://github.com/programasweights/programasweights"
|
|
187
|
-
target="_blank"
|
|
188
|
-
rel="noopener noreferrer"
|
|
189
|
-
className="flex items-center space-x-3 px-3 py-2.5 rounded-lg text-sm font-medium text-gray-600 hover:bg-gray-50 transition-colors"
|
|
190
|
-
>
|
|
191
|
-
<Github className="w-4 h-4" />
|
|
192
|
-
<span>GitHub</span>
|
|
193
|
-
</a>
|
|
194
|
-
{!user && (
|
|
195
|
-
<button
|
|
196
|
-
onClick={() => { handleLogin(); setMobileMenuOpen(false); }}
|
|
197
|
-
className="w-full flex items-center space-x-3 px-3 py-2.5 rounded-lg text-sm font-medium text-gray-600 hover:bg-gray-50 transition-colors"
|
|
198
|
-
>
|
|
199
|
-
<Github className="w-4 h-4" />
|
|
200
|
-
<span>Sign in with GitHub</span>
|
|
201
|
-
</button>
|
|
202
|
-
)}
|
|
203
147
|
</nav>
|
|
204
148
|
</div>
|
|
205
149
|
)}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import { Link } from 'react-router-dom';
|
|
3
|
+
import { Helmet } from 'react-helmet-async';
|
|
4
|
+
import { Search, ThumbsUp, Download, User, Clock, Package, TrendingUp, ArrowRight, Play } from 'lucide-react';
|
|
5
|
+
import { apiClient } from '../utils/api';
|
|
6
|
+
import type { ProgramSummary } from '../types';
|
|
7
|
+
|
|
8
|
+
function timeAgo(dateStr: string): string {
|
|
9
|
+
const seconds = Math.floor((Date.now() - new Date(dateStr).getTime()) / 1000);
|
|
10
|
+
if (seconds < 60) return 'just now';
|
|
11
|
+
const minutes = Math.floor(seconds / 60);
|
|
12
|
+
if (minutes < 60) return `${minutes}m ago`;
|
|
13
|
+
const hours = Math.floor(minutes / 60);
|
|
14
|
+
if (hours < 24) return `${hours}h ago`;
|
|
15
|
+
const days = Math.floor(hours / 24);
|
|
16
|
+
if (days < 30) return `${days}d ago`;
|
|
17
|
+
return new Date(dateStr).toLocaleDateString();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const HubPage: React.FC = () => {
|
|
21
|
+
const [programs, setPrograms] = useState<ProgramSummary[]>([]);
|
|
22
|
+
const [loading, setLoading] = useState(true);
|
|
23
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
24
|
+
const [sortBy, setSortBy] = useState<'popular' | 'recent' | 'downloads'>('popular');
|
|
25
|
+
const [selectedTag, setSelectedTag] = useState<string | null>(null);
|
|
26
|
+
|
|
27
|
+
useEffect(() => { loadPrograms(); }, [sortBy, selectedTag]);
|
|
28
|
+
|
|
29
|
+
const loadPrograms = async () => {
|
|
30
|
+
setLoading(true);
|
|
31
|
+
try {
|
|
32
|
+
const response = await apiClient.getPrograms({
|
|
33
|
+
sort: sortBy,
|
|
34
|
+
tag: selectedTag || undefined,
|
|
35
|
+
search: searchQuery || undefined,
|
|
36
|
+
});
|
|
37
|
+
setPrograms(response.programs);
|
|
38
|
+
} catch {
|
|
39
|
+
setPrograms([]);
|
|
40
|
+
} finally {
|
|
41
|
+
setLoading(false);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const handleSearch = (e: React.FormEvent) => {
|
|
46
|
+
e.preventDefault();
|
|
47
|
+
loadPrograms();
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const popularTags = ['nlp', 'extraction', 'classification', 'translation', 'code', 'math', 'reasoning'];
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<div className="max-w-6xl mx-auto space-y-8">
|
|
54
|
+
<Helmet>
|
|
55
|
+
<title>Program Hub — PAW</title>
|
|
56
|
+
<meta name="description" content="Discover, share, and download community-built neural programs." />
|
|
57
|
+
</Helmet>
|
|
58
|
+
|
|
59
|
+
<div className="flex flex-col sm:flex-row sm:items-end sm:justify-between gap-4">
|
|
60
|
+
<div>
|
|
61
|
+
<h1 className="text-3xl font-bold text-gray-900">Program Hub</h1>
|
|
62
|
+
<p className="text-gray-500 mt-1">Discover and download community-built neural programs</p>
|
|
63
|
+
</div>
|
|
64
|
+
<Link
|
|
65
|
+
to="/playground"
|
|
66
|
+
className="inline-flex items-center gap-2 px-5 py-2.5 bg-gray-900 text-white font-medium rounded-lg hover:bg-gray-800 transition-colors text-sm self-start sm:self-auto"
|
|
67
|
+
>
|
|
68
|
+
<Play className="w-4 h-4" />
|
|
69
|
+
Create Program
|
|
70
|
+
</Link>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
{/* Search */}
|
|
74
|
+
<form onSubmit={handleSearch} className="relative">
|
|
75
|
+
<Search className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400" />
|
|
76
|
+
<input
|
|
77
|
+
type="text"
|
|
78
|
+
value={searchQuery}
|
|
79
|
+
onChange={e => setSearchQuery(e.target.value)}
|
|
80
|
+
placeholder="Search programs..."
|
|
81
|
+
className="w-full pl-12 pr-24 py-3.5 rounded-xl border border-gray-200 bg-white text-gray-900 placeholder-gray-400 focus:ring-2 focus:ring-gray-900 focus:border-gray-900 outline-none transition-all shadow-sm"
|
|
82
|
+
/>
|
|
83
|
+
<button type="submit" className="absolute right-2 top-1/2 -translate-y-1/2 px-5 py-2 bg-gray-900 text-white text-sm font-medium rounded-lg hover:bg-gray-800 transition-colors">
|
|
84
|
+
Search
|
|
85
|
+
</button>
|
|
86
|
+
</form>
|
|
87
|
+
|
|
88
|
+
{/* Tags + Sort */}
|
|
89
|
+
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
|
|
90
|
+
<div className="flex flex-wrap gap-2">
|
|
91
|
+
<button
|
|
92
|
+
onClick={() => setSelectedTag(null)}
|
|
93
|
+
className={`px-3 py-1.5 rounded-full text-xs font-medium transition-all ${!selectedTag ? 'bg-gray-900 text-white' : 'bg-gray-100 text-gray-600 hover:bg-gray-200'}`}
|
|
94
|
+
>
|
|
95
|
+
All
|
|
96
|
+
</button>
|
|
97
|
+
{popularTags.map(tag => (
|
|
98
|
+
<button
|
|
99
|
+
key={tag}
|
|
100
|
+
onClick={() => setSelectedTag(selectedTag === tag ? null : tag)}
|
|
101
|
+
className={`px-3 py-1.5 rounded-full text-xs font-medium transition-all ${selectedTag === tag ? 'bg-gray-900 text-white' : 'bg-gray-100 text-gray-600 hover:bg-gray-200'}`}
|
|
102
|
+
>
|
|
103
|
+
{tag}
|
|
104
|
+
</button>
|
|
105
|
+
))}
|
|
106
|
+
</div>
|
|
107
|
+
<div className="flex items-center gap-1 bg-gray-100 rounded-lg p-1">
|
|
108
|
+
{(['popular', 'recent', 'downloads'] as const).map(sort => (
|
|
109
|
+
<button
|
|
110
|
+
key={sort}
|
|
111
|
+
onClick={() => setSortBy(sort)}
|
|
112
|
+
className={`px-3 py-1.5 rounded-md text-xs font-medium transition-all ${sortBy === sort ? 'bg-white text-gray-900 shadow-sm' : 'text-gray-500 hover:text-gray-700'}`}
|
|
113
|
+
>
|
|
114
|
+
{sort.charAt(0).toUpperCase() + sort.slice(1)}
|
|
115
|
+
</button>
|
|
116
|
+
))}
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
|
|
120
|
+
{/* Content */}
|
|
121
|
+
{loading ? (
|
|
122
|
+
<div className="space-y-4">
|
|
123
|
+
{[1, 2, 3].map(i => (
|
|
124
|
+
<div key={i} className="bg-white rounded-xl border border-gray-200 p-6 animate-pulse">
|
|
125
|
+
<div className="h-5 bg-gray-200 rounded w-1/3 mb-3" />
|
|
126
|
+
<div className="h-4 bg-gray-100 rounded w-2/3" />
|
|
127
|
+
</div>
|
|
128
|
+
))}
|
|
129
|
+
</div>
|
|
130
|
+
) : programs.length === 0 ? (
|
|
131
|
+
<div className="text-center py-16 bg-white rounded-xl border border-gray-200">
|
|
132
|
+
<Package className="w-12 h-12 text-gray-300 mx-auto mb-4" />
|
|
133
|
+
<h2 className="text-lg font-semibold text-gray-700 mb-2">No programs yet</h2>
|
|
134
|
+
<p className="text-gray-500 mb-6 text-sm">Be the first to compile a neural program!</p>
|
|
135
|
+
<Link to="/playground" className="inline-flex items-center gap-2 px-5 py-2.5 bg-gray-900 text-white rounded-lg hover:bg-gray-800 transition-colors text-sm font-medium">
|
|
136
|
+
<Play className="w-4 h-4" />
|
|
137
|
+
Open Playground
|
|
138
|
+
</Link>
|
|
139
|
+
</div>
|
|
140
|
+
) : (
|
|
141
|
+
<div className="space-y-3">
|
|
142
|
+
{programs.map(program => (
|
|
143
|
+
<Link
|
|
144
|
+
key={program.id}
|
|
145
|
+
to={`/hub/${program.id}`}
|
|
146
|
+
className="group flex items-center gap-5 bg-white rounded-xl border border-gray-200 px-5 py-4 hover:border-gray-300 hover:shadow-sm transition-all"
|
|
147
|
+
>
|
|
148
|
+
<div className="flex-1 min-w-0">
|
|
149
|
+
<h3 className="font-medium text-gray-900 group-hover:text-blue-600 transition-colors truncate">
|
|
150
|
+
{program.name || program.spec.slice(0, 60)}
|
|
151
|
+
</h3>
|
|
152
|
+
<p className="text-sm text-gray-500 truncate">{program.spec}</p>
|
|
153
|
+
<div className="flex items-center gap-3 mt-2">
|
|
154
|
+
<span className="text-xs text-gray-400 flex items-center gap-1">
|
|
155
|
+
<User className="w-3 h-3" />
|
|
156
|
+
{program.author || 'Anonymous'}
|
|
157
|
+
</span>
|
|
158
|
+
<span className="text-xs text-gray-400 flex items-center gap-1">
|
|
159
|
+
<Clock className="w-3 h-3" />
|
|
160
|
+
{timeAgo(program.created_at)}
|
|
161
|
+
</span>
|
|
162
|
+
{program.tags?.slice(0, 3).map(tag => (
|
|
163
|
+
<span key={tag} className="px-2 py-0.5 bg-gray-100 text-gray-500 text-[10px] rounded-full">{tag}</span>
|
|
164
|
+
))}
|
|
165
|
+
</div>
|
|
166
|
+
</div>
|
|
167
|
+
<div className="flex items-center gap-4 text-xs text-gray-400 flex-shrink-0">
|
|
168
|
+
<span className="flex items-center gap-1"><ThumbsUp className="w-3.5 h-3.5" />{program.upvotes}</span>
|
|
169
|
+
<span className="flex items-center gap-1"><Download className="w-3.5 h-3.5" />{program.downloads}</span>
|
|
170
|
+
<ArrowRight className="w-4 h-4 text-gray-300 group-hover:text-gray-500 transition-colors" />
|
|
171
|
+
</div>
|
|
172
|
+
</Link>
|
|
173
|
+
))}
|
|
174
|
+
</div>
|
|
175
|
+
)}
|
|
176
|
+
</div>
|
|
177
|
+
);
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
export default HubPage;
|