Metadata-Version: 2.4
Name: five9-wrapper
Version: 0.1.1
Summary: Internal wrapper to download Five9 report CSVs and call recordings.
Author: Andreu Bofi
License: Proprietary
Keywords: five9,call-center,recordings,api,soap,rest
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Intended Audience :: Developers
Classifier: License :: Other/Proprietary License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Communications :: Telephony
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: requests>=2.32.0

# api_five9

Internal Python library (WIP) to automate downloading Five9 call recordings (audio) using the Five9 APIs.
Intended to live in company GitLab and be cloned into other projects.

## Requirements
- Conda env: `five9`
- Python: 3.10+ (recommended)

## Install
```bash
conda activate five9
# Editable install (recommended for development / when cloning into other repos)
pip install -e .

# Or, install just the runtime dependency set
# pip install -r requirements.txt
```

## Publish to PyPI
There is a complete release guide in [`docs/PUBLISH_PYPI.md`](docs/PUBLISH_PYPI.md), including:
- required PyPI/TestPyPI tokens
- local `build` + `twine check`
- GitLab tag-based publication flow

## Configure credentials and endpoints
Create a local `.env` in the repo root (do **not** commit it):

```dotenv
FIVE9_USER=<five9_username>
FIVE9_PWD=<five9_password>
# Optional: override the SOAP endpoint (defaults to EU).
URL_FIVE9_API=https://api.eu.five9.com/wsadmin/v13/AdminWebService
```

Optional Supervisor REST overrides:

```dotenv
SUP_LOGIN_URL=https://app.<dc>.five9.com/supsvcs/rs/svc/auth/login
SUP_POLICY=ForceIn
SUP_STATION_TYPE=EMPTY
SUP_STATION_ID=
```

Notes:
- Credentials are read from environment variables (`FIVE9_USER`/`FIVE9_PWD`). For backwards compatibility the library also accepts `USER`/`PWD`.
- `URL_FIVE9_API` controls the SOAP Admin Web Services base endpoint (do not add `?user=...`; the client adds it).
- `SUP_LOGIN_URL` is data-center specific. Examples are listed in `web_docs/API _ Creating a Login Session using REST API.html`.

## Create the Report in Five9 (UI)
The Five9 SOAP reporting API can run and retrieve existing reports, but it does not provide a supported way to create or
edit report definitions (data source, columns, filters). You must create/configure the report manually in the Five9 UI.

This repo expects a custom report that includes at least a `call_id` column. For faster/more reliable downloads, include
`recording_id` and either `agent_id` or `agent email`.

Important concepts:
- `call_id` identifies the call session (this is typically what you get from reports).
- `recording_id` identifies the audio recording object (required by the download endpoint). A single `call_id` can have
  zero, one, or multiple `recording_id` values depending on how the call was handled.

### Mini tutorial (example)
1. Login to the Five9 VCC web UI.

   ![Five9 login](docs/screenshots/five9_01_login.png)

   Note: this repo includes placeholder screenshots so the README renders in GitLab. Replace them with real screenshots by running:
   `python scripts/capture_five9_report_tutorial_screenshots.py --manual --headful`

2. Go to the reporting area and open the report designer.

   ![Reporting area](docs/screenshots/five9_02_reporting.png)

3. Create (or reuse) a folder named `Joan_shared` and make it **public**.
   - The API user must have permission to access the report. Using a public folder is the simplest way to ensure the API
     can run the report without additional per-user sharing steps.

   ![Public folder](docs/screenshots/five9_03_public_folder.png)

4. Create a new custom report under `Joan_shared`.
5. Set the report **Data Source** to **Call Recording**.
   - `recording_id` is available from the "Call Recording" data source. Other data sources may not include it.

   ![Call Recording data source](docs/screenshots/five9_04_data_source_call_recording.png)

6. Add columns:
   - Required: `call_id` (or a localized equivalent such as "ID de llamada").
   - Recommended: `recording_id`, `agent_id`, `agent email`, and a time column like `Call Start`/`Timestamp`.
7. Save the report with a clear name (example: `call_id`).

### Using the report from this repo
- `--folder` should match the folder name (example: `Joan_shared`).
- `--report` should match the report name (example: `call_id`).

## Quickstart (download 1 audio from a report)
Downloads the recording referenced by one row in the report result (by default row 0):

```bash
python main.py --folder Joan_shared --report call_id --row-index 0 --out-dir data/downloads
```

Write the report result to CSV (metadata) and keep only selected columns:

```bash
python main.py --folder Joan_shared --report call_id --report-columns record_id,agent_id,campaign
```

Use a custom audio filename template:

```bash
python main.py --folder Joan_shared --report call_id --audio-name-template "{date}_{agent_id}_{call_id}.wav"
```

## Audio filename templates
Default is `{call_id}.wav`.

`--audio-name-template` uses Python `str.format` placeholders and must include `{call_id}` (or `{record_id}`) to avoid collisions.

Base placeholders always available:
- `{call_id}`, `{record_id}`, `{agent_id}`, `{recording_id}`
- `{date}` (YYYYMMDD), `{time}` (HHMMSS)
- `{call_dt}`, `{window_start}`, `{window_end}`, `{downloaded_at}` (datetime objects; you can format them like `{call_dt:%Y%m%d}`)

Additionally, report columns and recording metadata are exposed using snake_case keys (non-alphanumeric replaced with `_`).
Example: a report column named `Call Start` becomes `{call_start}`.

## Library usage (Python)
Download multiple recordings from a report window:

```python
from datetime import datetime, timezone, timedelta
from five9_wrapper import Five9Config, download_recordings_from_report

cfg = Five9Config.from_env(".env")
end = datetime.now(timezone.utc)
start = end - timedelta(hours=24)

result = download_recordings_from_report(
    cfg,
    folder="Joan_shared",
    report="call_id",
    start=start,
    end=end,
    # Optional: keep only these call/record IDs (client-side filter on the report result)
    call_ids=["100000000000001", "100000000000002"],
    out_dir="data/downloads",
    report_csv_path="data/downloads/report.csv",
    manifest_csv_path="data/downloads/manifest.csv",
    audio_name_template="{date}_{agent_id}_{call_id}.wav",
)
print(len(result.downloaded), "downloaded")
```

Download a report and keep only selected call IDs (metadata only):

```python
from datetime import datetime, timezone, timedelta
from five9_wrapper import Five9Config, AdminWebServiceClient

cfg = Five9Config.from_env(".env")
end = datetime.now(timezone.utc)
start = end - timedelta(hours=24)

soap = AdminWebServiceClient(cfg.soap)
report = soap.run_report_and_wait("Joan_shared", "call_id", start, end, call_ids=["100000000000001"])
report.write_csv("data/reports/call_id_filtered.csv")
```

Note: when `call_ids` is provided, the wrapper can split the time window to avoid Five9's SOAP row limits and return only
matching rows. This is still not true server-side filtering; configure report filters in Five9 when possible.

Download by explicit call/recording IDs:

```python
from five9_wrapper import Five9Config, download_recordings_by_ids

cfg = Five9Config.from_env(".env")
result = download_recordings_by_ids(cfg, ["100000000000001", "100000000000002"], out_dir="data/downloads")
```

## Repo layout
- `five9_wrapper/`: library code (SOAP reports + Supervisor REST + download orchestration).
- `main.py`: minimal CLI example (downloads 1 audio from a selected report row).
- `scripts/`: CLI helper scripts built on the library.
- `web_docs/`: vendor documentation snapshots (HTML + PDF).

## Scripts
Download only the report CSV (metadata):

```bash
python scripts/download_report_csv.py --folder Joan_shared --report call_id --today
```

Download only audios referenced by a report (with optional client-side filters):

```bash
python scripts/download_report_audios.py --folder Joan_shared --report call_id --today --out-dir data/downloads
```

Download both CSV + audios (opinionated "golden path"):
  - audio names: `{call_id}.wav`
  - report CSV contains only the `call_id` column (your report must include a `call_id` header)

```bash
python scripts/download_report_csv_and_audios.py --folder Joan_shared --report call_id --today
```

Download recordings for call IDs listed in a file (useful for backfills; auto-splits the window when SOAP results are truncated):

```bash
python scripts/download_call_ids_file.py --call-ids data/test_download/call_ids_extract.txt --months 6 --folder Joan_shared --report call_id
```

## Five9 API (high level)
This repo uses two Five9 APIs:

- **Admin Web Services (SOAP)** to run reports (`runReport` / `getReportResult`) and extract call/record IDs.
- **Supervisor REST + Streaming REST** to login, start a supervisor session, list recordings, and download bytes:
  - Login: `.../supsvcs/rs/svc/auth/login`
  - Start session: `.../supsvcs/rs/svc/supervisors/{userId}/session_start?force=true`
  - Check state: `.../supsvcs/rs/svc/supervisors/{userId}/login_state` (must be `WORKING`)
  - View recordings: `.../agents/{agentId}/recording_views`
  - Download: `.../strsvcs/rs/svc/agents/{agentId}/recordings/{recordingId}?download=true`

Important limitation:
- Five9's documented reporting API methods allow **running and retrieving** existing reports, but do **not** provide a
  supported way to **create/modify report definitions** (report folder + data source + columns + filters). Reports must
  be created/configured manually in the Five9 UI (see "Create the Report in Five9 (UI)").

For details, see `web_docs/` and the library implementation in `five9_wrapper/`.

## Tests

```bash
python -m unittest discover -s tests -v
```

## Notes for running from other folders
If you ran `pip install -e .`, you can import `five9_wrapper` from anywhere in the `five9` env.
If you only installed `requirements.txt`, run scripts from the repo root so Python can find `five9_wrapper/`.

## Generate `requirements.txt` (developer)
This repo keeps dependencies minimal. To regenerate `requirements.txt` using `pipreqs`:

```bash
pip install pipreqs
pipreqs . --force
```

## Troubleshooting
- If downloads fail with 401/unauthorized, ensure Supervisor metadata + session_start were performed (handled by `five9_wrapper`).
- Five9 may return MP3 bytes even when saving as `.wav` (vendor doc note). If you need format conversion, do it after download.
