> ## Documentation Index
> Fetch the complete documentation index at: https://doc.howen.ink/llms.txt
> Use this file to discover all available pages before exploring further.

# 내부 API

> 앱 프런트엔드가 호출하는 서버 API 라우트, 요청 매개변수, 공통 규칙을 알아봅니다.

앱의 서버 로직은 모두 `app/api/` 아래의 Next.js API 라우트에 있습니다. 프런트엔드는 이 라우트를 통해 모델 제공업체를 호출하고, 서버는 키 주입, API 주소 선택, 요청 매개변수 조정을 담당합니다.

<Note>
  이 라우트는 앱 내부 API로 주로 프런트엔드에서 사용하며, 매개변수는 버전에 따라 바뀔 수 있습니다. 다른 프로그램에서 호출하려면 저장소의 소스 코드를 기준으로 하세요.
</Note>

## 공통 규칙

### 요청 헤더

| 요청 헤더                            | 설명                                                                       |
| -------------------------------- | ------------------------------------------------------------------------ |
| `Content-Type: application/json` | 모든 `POST` 요청은 JSON 요청 본문을 사용합니다.                                         |
| `X-App-Locale`                   | 답변 언어: `zh-CN`(기본값), `zh-TW`, `en` 또는 `ko`. 번역, 뜻풀이, 대화 답변의 언어에 영향을 줍니다. |
| `Authorization: Bearer <key>`    | 선택 사항. 사용자 자신의 API 키. 생략하면 서버에 설정된 키를 사용합니다.                             |

### 공통 매개변수

모델 관련 라우트는 모두 다음 매개변수를 받습니다.

| 매개변수       | 타입       | 설명                                                     |
| ---------- | -------- | ------------------------------------------------------ |
| `provider` | `string` | `deepseek`(기본값) 또는 `gemini`. 잘못된 값은 `deepseek`로 처리합니다. |
| `model`    | `string` | 모델 이름. 사용 가능한 목록에 없으면 해당 제공업체의 기본 모델을 사용합니다.           |

<Warning>
  요청 본문에 `apiUrl`을 포함할 수 없습니다. 서버는 `400`을 반환하고 「客户端不再支持自定义 API URL，请在服务器环境变量中配置上游端点。」라는 메시지를 표시합니다(한국어 화면에서는 「사용자 지정 API URL은 서버 환경 변수에서 설정해 주세요.」). API 주소는 `DEEPSEEK_API_URL` 또는 `GEMINI_API_URL`로만 설정할 수 있습니다.
</Warning>

### 접속 인증

`CODE`를 설정하면 `/api/auth`와 `/api/umami/script`를 제외한 모든 라우트는 요청에 유효한 `ja_session` Cookie가 있어야 하며, 없으면 다음을 반환합니다.

```json theme={null}
{ "error": { "message": "请先通过密码验证" } }
```

### 오류 형식

오류가 발생하면 라우트는 해당 HTTP 상태 코드와 통일된 형식의 오류를 반환합니다.

```json theme={null}
{ "error": { "message": "未提供API密钥，请在设置中配置API密钥或联系管理员配置服务器密钥" } }
```

* `message`는 항상 간체 중국어 원문이며 `X-App-Locale`의 영향을 받지 않습니다. 프런트엔드가 알려진 오류를 화면 언어로 번역해 표시합니다.
* 모델 제공업체가 반환한 원본 오류 메시지는 그대로 전달되며, 프런트엔드가 번역하지 않습니다.
* 모델 제공업체의 응답이 60초를 넘으면 스트리밍이 아닌 요청은 `504`와 「上游接口请求超时，请稍后重试。」를 반환합니다.

### 스트리밍 응답

스트리밍 출력을 켜면 라우트는 상위 API의 OpenAI 호환 Server-Sent Events 스트림을 그대로 전달하며, `Content-Type`은 `text/event-stream`입니다. 끄면 상위 API의 전체 JSON 응답을 반환합니다.

스트리밍 출력에서 90초 동안 새 데이터가 없으면 서버는 스트림에 오류 이벤트를 보낸 뒤 연결을 종료합니다.

```text theme={null}
data: {"error":{"message":"上游流式响应空闲超时，请重试。"}}
```

## 라우트 목록

| 메서드            | 라우트                   | 용도                      |
| -------------- | --------------------- | ----------------------- |
| `POST`         | `/api/analyze`        | 문장 단어 분리와 후리가나          |
| `POST`         | `/api/translate`      | 문장 전체 번역                |
| `POST`         | `/api/word-detail`    | 단어 또는 여러 단어 어구 상세 설명    |
| `POST`         | `/api/image-to-text`  | 이미지 글자 추출               |
| `POST`         | `/api/chat`           | AI 일본어 도우미 대화           |
| `POST`         | `/api/tts`            | 음성 합성                   |
| `GET`          | `/api/daily-sentence` | 오늘의 문장 가져오기             |
| `GET` / `POST` | `/api/auth`           | 인증 상태 조회 / 접속 비밀번호 인증   |
| `GET`          | `/api/umami/script`   | 구성에 따라 Umami 로드 스크립트 출력 |

### POST /api/analyze

| 매개변수     | 타입        | 설명                           |
| -------- | --------- | ---------------------------- |
| `prompt` | `string`  | 필수. 원문이 포함된 분석 프롬프트.         |
| `stream` | `boolean` | 스트리밍으로 반환할지 여부. 기본값 `false`. |

모델은 `{"tokens": [{"word", "pos", "furigana"}]}` 형태의 구조화된 JSON을 반환합니다.

### POST /api/translate

| 매개변수     | 타입        | 설명                           |
| -------- | --------- | ---------------------------- |
| `text`   | `string`  | 필수. 번역할 일본어 원문.              |
| `stream` | `boolean` | 스트리밍으로 반환할지 여부. 기본값 `false`. |

번역 언어는 `X-App-Locale`에 따라 결정되며, 원문의 단락과 줄바꿈 구조를 유지합니다.

### POST /api/word-detail

| 매개변수        | 타입        | 설명                                     |
| ----------- | --------- | -------------------------------------- |
| `word`      | `string`  | 필수. 선택한 단어 또는 어구.                      |
| `sentence`  | `string`  | 필수. 단어가 있는 문장 또는 문맥.                   |
| `pos`       | `string`  | 단어일 때 필수. 분석으로 얻은 품사.                  |
| `furigana`  | `string`  | 선택 사항. 분석으로 얻은 읽기.                     |
| `kind`      | `string`  | 선택 사항. `phrase`로 설정하면 여러 단어 어구로 분석합니다. |
| `useStream` | `boolean` | 스트리밍으로 반환할지 여부. 기본값 `false`.           |

단어 상세 설명은 `chineseTranslation`, `dictionaryForm`, `explanation`, `conjugation`, `example`, `exampleTranslation`, `pos`, `furigana` 필드를 반환합니다. 어구 상세 설명은 `category`와 `breakdown`을 추가로 반환합니다.

### POST /api/image-to-text

| 매개변수        | 타입        | 설명                           |
| ----------- | --------- | ---------------------------- |
| `imageData` | `string`  | 필수. 이미지의 Data URL. 8 MB 이하.  |
| `prompt`    | `string`  | 추출 지시문.                      |
| `stream`    | `boolean` | 스트리밍으로 반환할지 여부. 기본값 `false`. |

### POST /api/chat

| 매개변수        | 타입        | 설명                                   |
| ----------- | --------- | ------------------------------------ |
| `messages`  | `array`   | 필수. OpenAI 형식의 메시지 목록. 비어 있으면 안 됩니다. |
| `useStream` | `boolean` | 스트리밍으로 반환할지 여부. 기본값 `true`.          |

서버는 메시지 목록 앞에 일본어 학습 도우미용 시스템 프롬프트를 추가합니다.

### POST /api/tts

| 매개변수       | 타입       | 설명                                                                           |
| ---------- | -------- | ---------------------------------------------------------------------------- |
| `text`     | `string` | 필수. 읽을 텍스트.                                                                  |
| `provider` | `string` | `edge`(기본값) 또는 `gemini`.                                                     |
| `gender`   | `string` | Edge TTS에서 사용. `female`(기본값) 또는 `male`.                                      |
| `rate`     | `number` | Edge TTS에서 사용. 읽기 속도, 기본값 `0`.                                               |
| `voice`    | `string` | Gemini TTS에서 사용. `Kore`(기본값), `Puck`, `Zephyr`, `Aoede`, `Leda` 또는 `Charon`. |

성공하면 Base64로 인코딩된 오디오를 반환합니다.

```json theme={null}
{ "audio": "<base64>", "mimeType": "audio/mp3" }
```

### GET /api/daily-sentence

그날(일본 시간)의 오늘의 문장을 반환하며 `date`, `text`, `tokens`와 네 가지 언어의 `translation`을 포함합니다. 응답의 `Cache-Control`은 일본 시간 자정까지 유효합니다. 서버에 사용 가능한 키가 없거나 생성에 실패하면 `503`을 반환하고, 프런트엔드는 내장된 예비 문장을 사용합니다.

### /api/auth

* `GET`: `{ "requiresAuth": boolean, "authenticated": boolean }`을 반환합니다.
* `POST`: 요청 본문은 `{ "password": "..." }`입니다. 비밀번호가 맞으면 `{ "success": true }`를 반환하고 세션 Cookie를 기록하며, 틀리면 `401`을 반환합니다.
