# Korean Notice Evidence (`teal_blacksmith/korean-notice-evidence`) Actor

Extract deadline, eligibility and submission requirement candidates from Korean notice text or public HTML. Get exact supporting quotes, text offsets and date uncertainties as JSON. No LLM key required. Does not read PDF/HWP attachments or decide eligibility.

- **URL**: https://apify.com/teal_blacksmith/korean-notice-evidence.md
- **Developed by:** [도영 김](https://apify.com/teal_blacksmith) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 notice processeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Korean Notice Evidence Extractor

Turn Korean notice text or public HTML URLs into reviewable deadline and submission-requirement **candidates**, with exact supporting text spans. No LLM, external model key, or inferred final deadline.

This is version 0.1. Market demand and paid conversion have not been validated. Code created before November 13, 2026 is preexisting work for any later Apart Research sprint; it is not sprint research or an experimental result.

### Input and local use

Node.js 22 or newer. The extraction CLI uses only Node built-ins. Install the pinned dependencies with `npm ci` before running tests, which also exercise the Apify SDK with in-memory storage and API substitutes:

```sh
npm test
node src/cli.mjs examples/input.json
```

For the Apify runtime, install the pinned SDK using `npm ci`, then use `npm start` with standard Apify INPUT storage. `npm run local -- input.json` prints JSONL without an Apify account. See [example input](examples/input.json).

```json
{"sources":[{"id":"my-notice","text":"접수마감: 2026.11.15 18:00\n제출서류: PDF, 8페이지 이내"}]}
```

Supply exactly one of `text` or `url` per source. Optional `html: true` interprets supplied text as HTML. Maximum 50 sources, 200,000 text characters per source, 2 MB downloaded per URL, 100 matching evidence lines per result. URL mode fetches one public HTML or plain-text page, checks each redirect, pins validated public IPv4 DNS answers, and uses no cookies, credentials, proxies, or browser. IPv6-only hosts are unsupported. Server-declared character sets are decoded with `TextDecoder`; absent charset means UTF-8. Respect the source's access and reuse terms; prefer supplied licensed text when uncertain.

### Output contract

Each processed input becomes one dataset item. `text` is canonicalized line-based text; `textSha256` binds that version. For every `evidence` entry, `text.slice(start, end) === quote`. Offsets are JavaScript UTF-16 code units, end exclusive, referring to returned `text`, not raw HTML bytes. Categories include deadline, eligibility, deliverable, format, submission, AI policy, fees and rights. Date candidates preserve explicit components and report missing year/time/timezone or invalid calendar values. `finalDeadline` always remains `null`; a reviewer resolves competing dates and applicable rules.

An empty candidate list does not establish that a requirement is absent. HTML stripping is a simple text transform, not a full rendered-page parser. Dates must occur on a line containing supported deadline wording. No attachments, PDFs, HWP files, linked rules, OCR, Javascript-only pages, or legal interpretation. Pattern matches can be false positives. Do not use candidates as an automatic eligibility or deadline decision.

### Apify deployment and pricing

The [Actor definition](.actor/actor.json), [input schema](.actor/INPUT_SCHEMA.json), [Dockerfile](Dockerfile), and lockfile are included. Apify cloud build and synthetic runs have been verified. On October 29, a four-source cloud test produced two successful results and stopped at the configured $0.004 event budget. See [verification](VALIDATION.md). This is a developer test, not customer revenue or proof of market demand.

Pricing: **$0.002 per successfully processed notice ($2 / 1,000)**, including notices with zero candidate lines because inspection was performed. Platform usage is included in the listed price. URL failures and empty/unparseable supplied HTML are written to key-value `ERRORS` and incur no custom event. Invalid batch input fails before work.

The active Console configuration uses the single primary event `notice-processed` (“Notice processed”) at USD 0.002. Synthetic `apify-default-dataset-item` and `apify-actor-start` prices are removed. The loop stops on the SDK's spending-limit signal. Developer runs are not proof of a real customer's charge or payout.

Safety behavior in version 0.1: `charge-guard.mjs` requires an explicit finite budget and compares the next total event cost against it using exact decimal arithmetic before each save. It also checks SDK capacity and verifies that the named event count increased by one. This blocks SDK 3.7.0's first-event exception and rounded capacity near a price boundary, including a $0.00199999 budget for a $0.002 event. Cloud build 0.1.1 verified normal processing, rejection of a resurrected run, and zero events for the near-boundary budget. No Console pricing was changed.

The Apify entrypoint persists `NOTICE_PROCESSING_STARTED` before processing. An existing marker, dataset item, or named event charge disables automatic retry, including after migration or restart. Completed and partially completed runs keep the marker. Inspect previous output, charges, and key-value `ERRORS` before explicitly starting a new run with fresh storage; blindly resubmitting completed inputs can charge them again. `runSources` still supports partial batches and stops at the budget signal.

Dataset storage and event charging are **not atomic** in SDK 3.7.0: output is saved before the charge request. A failed or interrupted charge may leave an output item with an unknown or missing charge. The code records runtime errors in `ERRORS` when storage is available and blocks replay; it cannot roll back an item or guarantee exactly-once billing. A hard termination may prevent `ERRORS` from being written. This guard assumes one process per run and persistent default storage; it is not a lock for concurrent processes. Cloud resurrection was verified; live migration and an injected Cloud charge failure remain unverified. Local tests cover a charge failure using the actual SDK with storage and API substitutes.

Official implementation references: [actor.json contract](https://docs.apify.com/actors/development/actor-definition/actor-json), [input schema](https://docs.apify.com/actors/development/actor-definition/input-schema), [PPE behavior](https://docs.apify.com/actors/monetize/pay-per-event), [SDK PPE](https://docs.apify.com/sdk/js/docs/concepts/pay-per-event), [Actor SDK](https://docs.apify.com/sdk/js/reference/class/Actor). See [research and licensing notes](RESEARCH.md) and [verification](VALIDATION.md).

Original package code is available under the [MIT License](LICENSE). The Apify SDK is separately licensed under Apache-2.0; see [third-party notices](THIRD_PARTY_NOTICES.md). No Galaxy Con application core or third-party Actor code was copied.

# Actor input Schema

## `sources` (type: `array`):

1–50 objects. Each object has exactly one of text (max 200000 characters) or url (public HTTP(S)). Optional id (max 200 characters) and html boolean for supplied HTML. No attachments or browser execution.

## Actor input object example

```json
{
  "sources": [
    {
      "id": "example",
      "text": "접수마감: 2026.11.15 18:00\n제출서류: PDF 1개, 8페이지 이내"
    }
  ]
}
```

# Actor output Schema

## `results` (type: `string`):

One dataset item per successfully processed notice, including notices with no candidates. Evidence spans refer to the returned text; finalDeadline remains null and requires human review.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "sources": [
        {
            "id": "example",
            "text": "접수마감: 2026.11.15 18:00\n제출서류: PDF 1개, 8페이지 이내"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("teal_blacksmith/korean-notice-evidence").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "sources": [{
            "id": "example",
            "text": """접수마감: 2026.11.15 18:00
제출서류: PDF 1개, 8페이지 이내""",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("teal_blacksmith/korean-notice-evidence").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "sources": [
    {
      "id": "example",
      "text": "접수마감: 2026.11.15 18:00\\n제출서류: PDF 1개, 8페이지 이내"
    }
  ]
}' |
apify call teal_blacksmith/korean-notice-evidence --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,teal_blacksmith/korean-notice-evidence"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/XYXLYxGiQGEq7IPro/builds/meixyGaqhhbGIc5SR/openapi.json
