Files

1 line
7.2 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "ayhm23/resume-env", "files": {"README.md": {"c6060376e72d44bb73ab525b651a2d96de95c588": {"t": 1785846879.0244856, "n": 6727, "h": "a1b082443e95bab3", "c": "---\ntitle: resume-env\nemoji: 📄\ncolorFrom: blue\ncolorTo: green\nsdk: docker\napp_port: 8000\ntags:\n - rl-environment\n - resume\n - ats\n - job-application\nlicense: bsd-3-clause\n---\n\n# ResumeEnv 🎯\n**Job Application Optimizer — OpenEnv Environment**\n\nAn OpenEnv-compliant environment where an AI agent reads a job description and a candidate resume, then optimizes the resume and cover letter to maximize ATS (Applicant Tracking System) match rate.\n\n---\n\n## Install & Run\n\n```bash\n# Install client\npip install git+https://huggingface.co/spaces/ayhm23/resume-env\n\n# Run locally with Docker\ndocker build -t resume-env .\ndocker run -p 8000:8000 resume-env\n```\n\n## Quick Start\n\n```python\nimport asyncio\nfrom resume_env import ResumeEnv, ResumeAction\n\nasync def main():\n async with ResumeEnv(base_url=\"https://ayhm23-resume-env.hf.space\") as env:\n\n # Task 1 — Keyword Extraction\n result = await env.reset(task_id=\"task1_keyword_extraction\")\n print(result.observation.job_description)\n\n result = await env.step(ResumeAction(\n action_type=\"extract_keywords\",\n hard_skills=[\"SQL\", \"Python\", \"Tableau\"],\n soft_skills=[\"stakeholder communication\"],\n experience_years=5,\n ))\n print(f\"Score: {result.reward}\") # e.g. 0.78\n\nasyncio.run(main())\n\n# Sync usage\nfrom resume_env import ResumeEnv, ResumeAction\nwith ResumeEnv(base_url=\"http://localhost:8000\").sync() as env:\n result = env.reset(task_id=\"task2_bullet_rewrite\")\n result = env.step(ResumeAction(\n action_type=\"rewrite_bullet\",\n rewritten_bullet=\"Developed Tableau dashboards tracking 12 KPIs...\",\n ))\n print(result.reward)\n```\n\n---\n\n## API Endpoints\n\n| Endpoint | Method | Description |\n|-------------|--------|-------------|\n| `/reset` | POST | Start new episode. Body: `{\"task_id\": \"task1_keyword_extraction\"}` |\n| `/step` | POST | Submit action, get observation + reward |\n| `/state` | GET | Episode metadata (step_count, episode_id, cumulative_reward) |\n| `/tasks` | GET | List all tasks with action schemas |\n| `/grader` | GET | Last episode grader scores |\n| `/baseline` | POST | Run rule-based baseline on all 3 tasks |\n| `/health` | GET | `{\"status\": \"ok\"}` |\n| `/ws` | WS | WebSocket (used by Python client) |\n| `/web` | GET | Interactive browser UI |\n\n---\n\n## Tasks\n\n### Task 1 — Keyword Extraction (Easy) · max_steps=1\n\n**Goal:** Extract structured skills from a job description.\n\n**Action:**\n```json\n{\n \"action_type\": \"extract_keywords\",\n \"hard_skills\": [\"SQL\", \"Python\", \"Tableau\"],\n \"soft_skills\": [\"stakeholder communication\"],\n \"experience_years\": 5\n}\n```\n\n**Reward:** `0.60 × hard_skill_F1 + 0.25 × soft_skill_Jaccard + 0.15 × experience_accuracy`\n\n---\n\n### Task 2 — Bullet Rewrite (Medium) · max_steps=1\n\n**Goal:** Rewrite one resume bullet for maximum ATS match.\n\n**Action:**\n```json\n{\n \"action_type\": \"rewrite_bullet\",\n \"rewritten_bullet\": \"Developed Tableau dashboards tracking 12 KPIs, reducing reporting time by 40%.\"\n}\n```\n\n**Reward:** `0.40 × ATS_improvement + 0.30 × semantic_preservation + 0.30 × quality`\n\nQuality = strong action verb (0.5) + quantification present (0.5).\n\n---\n\n### Task 3 — Full Application Pack (Hard) · max_steps=4\n\n**Goal:** Build a complete tailored application in 4 sequential steps.\n\n| Step | action_type | content |\n|------|-------------|---------|\n| 1 | `rewrite_summary` | New 2-sentence professional summary |\n| 2 | `rewrite_experience` | Rewritten bullets, one per line |\n| 3 | `update_skills` | Comma-separated updated skills list |\n| 4 | `write_cover_letter` | Full cover letter starting with \"Dear Hiring Manager,\" |\n\n**Final Reward:** `0.35 × resume_ATS + 0.25 × cover_relevance + 0.25 × keyword_coverage + 0.15 × format_score`\n\nPartial rewards are given after each step.\n\n---\n\n## Observation Space\n\nEvery observation (`ResumeObservation`) contains:\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `task_id` | str | Current task |\n| `job_description` | str | Full JD text |\n| `resume_snapshot` | dict | Current resume state |\n| `feedback` | str | Human-readable score breakdown |\n| `current_score` | float | Score so far |\n| `steps_remaining` | int | Steps left in episode |\n| `done` | bool | Episode complete |\n| `reward` | float | Step reward |\n| `metadata` | dict | Detailed grader breakdown |\n\n---\n\n## Environment Variables\n\n`inference.py` reads these from the shell environment (or a `.env` file):\n\n| Variable | Required | Description | Example |\n|----------|----------|-------------|---------|\n| `HF_TOKEN` | **Yes** | Your API key (HF or Groq or OpenAI) | `hf_...` / `gsk_...` / `sk-...` |\n| `API_BASE_URL` | No | LLM provider endpoint. **If unset**, the OpenAI SDK defaults to `https://api.openai.com/v1` | `https://api.groq.com/openai/v1` |\n| `MODEL_NAME` | No | Model identifier for the chosen provider. Default: `gpt-4o-mini` | `llama-3.3-70b-versatile` |\n| `ENV_BASE_URL` | No | Running ResumeEnv server. Default: `http://localhost:8000` | `https://ayhm23-resume-env.hf.space` |\n\n> **Note:** `OPENAI_API_KEY` is also accepted as an alias for `HF_TOKEN`.\n\n### Using Groq\n```bash\nexport HF_TOKEN=gsk_...\nexport API_BASE_URL=https://api.groq.com/openai/v1\nexport MODEL_NAME=llama-3.3-70b-versatile\npython inference.py\n```\n\n### Using OpenAI\n```bash\nexport HF_TOKEN=sk-...\n# API_BASE_URL not needed — SDK defaults to api.openai.com\nexport MODEL_NAME=gpt-4o-mini\npython inference.py\n```\n\n---\n\n## Baseline\n\n```bash\n# Rule-based (no LLM, always works)\ncurl -X POST http://localhost:8000/baseline\n\n# LLM baseline\nexport OPENAI_API_KEY=sk-...\nexport MODEL_NAME=gpt-4o-mini\npython inference.py\n```\n\nExpected baseline scores:\n\n| Task | Rule-based | LLM (gpt-4o-mini) |\n|------|-----------|-------------------|\n| Task 1 | ~0.48 | ~0.80 |\n| Task 2 | ~0.55 | ~0.72 |\n| Task 3 | ~0.38 | ~0.65 |\n\n---\n\n## Project Structure\n\n```\nresume_env/\n├── __init__.py ← exports ResumeAction, ResumeObservation, ResumeState, ResumeEnv\n├── models.py ← Action / Observation / State dataclasses\n├── client.py ← ResumeEnv(HTTPEnvClient)\n├── inference.py ← LLM baseline agent (OpenAI-compatible)\n├── openenv.yaml ← OpenEnv manifest\n├── pyproject.toml\n├── .dockerignore\n├── README.md\n└── server/\n ├── __init__.py\n ├── resume_environment.py ← ResumeEnvironment (reset / step / state)\n ├── app.py ← FastAPI (create_web_interface_app + /tasks /grader /baseline)\n ├── requirements.txt ← server deps (no ML libraries)\n └── Dockerfile\n```\n\n---\n\n## Deploy\n\n```bash\ncd resume_env\nopenenv push --repo-id ayhm23/resume-env\n```\n\n---\n\n## License\nBSD-3-Clause\n"}}}}