# hasanazir1/ai-opportunity-agent architecture

> Architecture diagram of the GitHub repository hasanazir1/ai-opportunity-agent, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-28). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/hasanazir1/ai-opportunity-agent
- Repository: https://github.com/hasanazir1/ai-opportunity-agent

## Overview

AI Opportunity Agent is an Arabic Flask web app that turns an uploaded text-based CV into ranked job matches, then lets the user explore results and request job-specific help. Its main workflow extracts CV text, analyzes it, embeds the profile, fetches jobs, ranks candidates by cosine similarity, and asks an LLM to score shortlisted matches; saved results and progress appear in the browser. Separate chat roles answer questions, suggest CV edits, and draft cover letters. The graph reflects README capabilities; omitted app code limits certainty about some internal call details.

Main entry points: [`flask_app/app.py`](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/app.py) (Flask workflow), [`flask_app/utils/llm_service.py`](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/utils/llm_service.py) (Chat model client), [`flask_app/database/db.py`](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/database/db.py) (SQLite data access), [`flask_app/utils/prompts.py`](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/utils/prompts.py) (Role prompts)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_interface["Web interface"]
  node_browser["Arabic interface<br/>[index.html]"]
  node_client["Browser client<br/>[main.js]"]
  node_app["Flask workflow<br/>[app.py]"]
  node_progress["Live progress events<br/>[app.py]"]
end

subgraph group_analysis["CV and matching"]
  node_pdf["PDF extraction<br/>[pdf_parser.py]"]
  node_cv_agent["CV analysis expert<br/>[cv_analyzer.py]"]
  node_embedding["Embedding service"]
  node_jobs_fetcher["Job feed and fallback<br/>[jobs_fetcher.py]"]
  node_ranking["Semantic shortlist"]
  node_scorer["Match scoring expert<br/>[match_scorer.py]"]
end

subgraph group_chat["Chat assistance"]
  node_orchestrator["Chat orchestrator"]
  node_query["Chat query expert<br/>[chat_query.py]"]
  node_improvement["CV improvement expert<br/>[cv_improvement.py]"]
  node_letter["Cover letter expert<br/>[cover_letter.py]"]
end

subgraph group_services["Integrations and storage"]
  node_prompts["Role prompts<br/>[prompts.py]"]
  node_llm["Chat model client<br/>[llm_service.py]"]
  node_db[("SQLite data access<br/>[db.py]")]
end

node_user(("CV user"))
node_rss["Jobs.ps RSS"]
node_openrouter{{"OpenRouter API"}}

node_user -->|"uploads CV"| node_browser
node_browser -->|"submits actions"| node_client
node_client -->|"sends requests"| node_app
node_app -->|"extracts text"| node_pdf
node_app -->|"creates profile"| node_db
node_app -->|"analyzes CV"| node_cv_agent
node_cv_agent -->|"builds prompt"| node_prompts
node_cv_agent -->|"requests analysis"| node_llm
node_app -->|"embeds profile"| node_embedding
node_app -->|"fetches listings"| node_jobs_fetcher
node_jobs_fetcher -.->|"reads feed"| node_rss
node_jobs_fetcher -->|"reads cached jobs"| node_db
node_app -->|"stores profile analysis"| node_db
node_app -->|"ranks job vectors"| node_ranking
node_ranking -->|"creates missing vectors"| node_embedding
node_ranking -->|"reads and saves vectors"| node_db
node_app -->|"evaluates shortlist"| node_scorer
node_scorer -->|"builds prompt"| node_prompts
node_scorer -->|"scores match"| node_llm
node_app -->|"saves match results"| node_db
node_app -->|"emits status"| node_progress
node_progress -->|"streams updates"| node_client
node_app -->|"routes free message"| node_orchestrator
node_app -->|"handles direct question"| node_query
node_app -->|"handles CV request"| node_improvement
node_app -->|"handles letter request"| node_letter
node_orchestrator -->|"builds prompt"| node_prompts
node_orchestrator -->|"selects expert"| node_llm
node_query -->|"reads saved matches"| node_db
node_query -->|"builds prompt"| node_prompts
node_query -->|"answers question"| node_llm
node_improvement -->|"builds prompt"| node_prompts
node_improvement -->|"suggests edits"| node_llm
node_letter -->|"reads role settings"| node_db
node_letter -->|"builds prompt"| node_prompts
node_letter -->|"drafts letter"| node_llm
node_llm -->|"sends completion"| node_openrouter
node_embedding -->|"requests vectors"| node_openrouter
node_llm -->|"returns assistant text"| node_client
node_db -->|"serves saved results"| node_client

click node_browser "https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/templates/index.html"
click node_client "https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/static/js/main.js"
click node_app "https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/app.py"
click node_pdf "https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/utils/pdf_parser.py"
click node_cv_agent "https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/agents/cv_analyzer.py"
click node_embedding "https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/utils/embedding_service.py"
click node_jobs_fetcher "https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/utils/jobs_fetcher.py"
click node_ranking "https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/utils/embedding_service.py"
click node_scorer "https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/agents/match_scorer.py"
click node_orchestrator "https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/agents/chat_orchestrator.py"
click node_query "https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/agents/chat_query.py"
click node_improvement "https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/agents/cv_improvement.py"
click node_letter "https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/agents/cover_letter.py"
click node_prompts "https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/utils/prompts.py"
click node_llm "https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/utils/llm_service.py"
click node_db "https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/database/db.py"
click node_progress "https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/app.py"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_browser,node_client,node_app,node_progress,node_user toneBlue
class node_pdf,node_cv_agent,node_embedding,node_jobs_fetcher,node_ranking,node_scorer toneAmber
class node_orchestrator,node_query,node_improvement,node_letter,node_openrouter toneMint
class node_prompts,node_llm,node_db toneRose
class node_rss toneIndigo
```

## Components

### Web interface

- [Arabic interface](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/templates/index.html): `flask_app/templates/index.html`
- [Browser client](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/static/js/main.js): `flask_app/static/js/main.js`
- [Flask workflow](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/app.py): `flask_app/app.py`
- [Live progress events](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/app.py): `flask_app/app.py`

### CV and matching

- [PDF extraction](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/utils/pdf_parser.py): `flask_app/utils/pdf_parser.py`
- [CV analysis expert](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/agents/cv_analyzer.py): `flask_app/agents/cv_analyzer.py`
- [Embedding service](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/utils/embedding_service.py): `flask_app/utils/embedding_service.py`
- [Job feed and fallback](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/utils/jobs_fetcher.py): `flask_app/utils/jobs_fetcher.py`
- [Semantic shortlist](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/utils/embedding_service.py): `flask_app/utils/embedding_service.py`
- [Match scoring expert](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/agents/match_scorer.py): `flask_app/agents/match_scorer.py`

### Chat assistance

- [Chat orchestrator](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/agents/chat_orchestrator.py): `flask_app/agents/chat_orchestrator.py`
- [Chat query expert](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/agents/chat_query.py): `flask_app/agents/chat_query.py`
- [CV improvement expert](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/agents/cv_improvement.py): `flask_app/agents/cv_improvement.py`
- [Cover letter expert](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/agents/cover_letter.py): `flask_app/agents/cover_letter.py`

### Integrations and storage

- [Role prompts](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/utils/prompts.py): `flask_app/utils/prompts.py`
- [Chat model client](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/utils/llm_service.py): `flask_app/utils/llm_service.py`
- [SQLite data access](https://github.com/hasanazir1/ai-opportunity-agent/blob/main/flask_app/database/db.py): `flask_app/database/db.py`

### Other components

- **CV user**
- **Jobs.ps RSS**
- **OpenRouter API**

## Connections

- CV user → Arabic interface: uploads CV
- Arabic interface → Browser client: submits actions
- Browser client → Flask workflow: sends requests
- Flask workflow → PDF extraction: extracts text
- Flask workflow → SQLite data access: creates profile
- Flask workflow → CV analysis expert: analyzes CV
- CV analysis expert → Role prompts: builds prompt
- CV analysis expert → Chat model client: requests analysis
- Flask workflow → Embedding service: embeds profile
- Flask workflow → Job feed and fallback: fetches listings
- Job feed and fallback → Jobs.ps RSS: reads feed
- Job feed and fallback → SQLite data access: reads cached jobs
- Flask workflow → SQLite data access: stores profile analysis
- Flask workflow → Semantic shortlist: ranks job vectors
- Semantic shortlist → Embedding service: creates missing vectors
- Semantic shortlist → SQLite data access: reads and saves vectors
- Flask workflow → Match scoring expert: evaluates shortlist
- Match scoring expert → Role prompts: builds prompt
- Match scoring expert → Chat model client: scores match
- Flask workflow → SQLite data access: saves match results
- Flask workflow → Live progress events: emits status
- Live progress events → Browser client: streams updates
- Flask workflow → Chat orchestrator: routes free message
- Flask workflow → Chat query expert: handles direct question
- Flask workflow → CV improvement expert: handles CV request
- Flask workflow → Cover letter expert: handles letter request
- Chat orchestrator → Role prompts: builds prompt
- Chat orchestrator → Chat model client: selects expert
- Chat query expert → SQLite data access: reads saved matches
- Chat query expert → Role prompts: builds prompt
- Chat query expert → Chat model client: answers question
- CV improvement expert → Role prompts: builds prompt
- CV improvement expert → Chat model client: suggests edits
- Cover letter expert → SQLite data access: reads role settings
- Cover letter expert → Role prompts: builds prompt
- Cover letter expert → Chat model client: drafts letter
- Chat model client → OpenRouter API: sends completion
- Embedding service → OpenRouter API: requests vectors
- Chat model client → Browser client: returns assistant text
- SQLite data access → Browser client: serves saved results
