{"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"}}}}