File size: 4,547 Bytes
00255a8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
"""Palette-K-Midm live demo — 회의록 → 결정사항 추출 (PALETTE-BENCH-KO #1 model).

HF Space (ZeroGPU). Deploy: upload this folder as a Gradio Space, hardware = ZeroGPU.
"""
import json
import re

import gradio as gr
import spaces
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

MODEL_ID = "imcapsule/palette-k-midm"  # TODO: replace ORG on drop day

tok = AutoTokenizer.from_pretrained(MODEL_ID)
model = AutoModelForCausalLM.from_pretrained(
    MODEL_ID, torch_dtype=torch.bfloat16, device_map="auto"
)

PROMPT = """다음 회의록에서 결정사항을 추출하라.

규칙:
- 실제로 확정된 결정만 포함한다. 보류/검토중/논의만 된 항목은 제외한다.
- 각 결정에 담당자(owner)와 기한(due_date, YYYY-MM-DD)을 붙인다. 기한이 명시되지 않았으면 null.
- 상대 날짜("다음 주 금요일까지")는 회의 날짜 기준으로 환산한다.
- JSON만 출력한다: {{"decisions": [{{"decision": "...", "owner": "...", "due_date": "..."}}]}}

회의록:
{minutes}"""

EXAMPLE = """[주간 운영회의] 2026-08-17 (월) 14:00 · 참석: 김부장, 이과장, 박대리, 최주임

김부장: 3분기 예산안은 지난주 논의대로 확정합니다. 이과장이 이번 주 금요일까지 품의서 올려주세요.
이과장: 네. 그리고 신규 거래처 계약 건은 법무 검토가 아직이라 다음 회의로 넘기겠습니다.
박대리: 사무실 이전 견적 3곳 받았습니다. 비교표는 제가 정리 중입니다.
김부장: 비교표는 정리되는 대로 공유만 해주세요. 아, 그리고 전사 보안교육은 9월 5일로 확정. 최주임이 공지 담당.
최주임: 알겠습니다."""


def _extract_json(s: str):
    start = s.find("{")
    while start != -1:
        depth, in_str, esc = 0, False, False
        for i in range(start, len(s)):
            c = s[i]
            if in_str:
                if esc:
                    esc = False
                elif c == "\\":
                    esc = True
                elif c == '"':
                    in_str = False
                continue
            if c == '"':
                in_str = True
            elif c == "{":
                depth += 1
            elif c == "}":
                depth -= 1
                if depth == 0:
                    try:
                        return json.loads(s[start : i + 1])
                    except Exception:
                        break
        start = s.find("{", start + 1)
    return None


@spaces.GPU(duration=60)
def extract(minutes: str):
    if not minutes.strip():
        return "회의록을 입력하세요.", ""
    msgs = [{"role": "user", "content": PROMPT.format(minutes=minutes.strip())}]
    ids = tok.apply_chat_template(
        msgs, return_tensors="pt", add_generation_prompt=True
    ).to(model.device)
    out = model.generate(ids, max_new_tokens=800, do_sample=False)
    text = tok.decode(out[0][ids.shape[-1]:], skip_special_tokens=True)
    parsed = _extract_json(text)
    if parsed and "decisions" in parsed:
        rows = "\n".join(
            f"| {d.get('decision','')} | {d.get('owner','')} | {d.get('due_date') or '—'} |"
            for d in parsed["decisions"]
        )
        table = "| 결정사항 | 담당자 | 기한 |\n|---|---|---|\n" + rows
        return table, text
    return "JSON 파싱 실패 — 원문 출력을 확인하세요.", text


with gr.Blocks(title="Palette-K-Midm · 회의록→결정 추출") as demo:
    gr.Markdown(
        "# Palette-K-Midm — 회의록에서 결정사항 추출\n"
        "PALETTE-BENCH-KO **1위 (0.866)** 모델의 라이브 데모. "
        "보류·논의중 항목 제외, 상대 날짜 환산, 기한 없으면 null — "
        "전 모델 공통 난제 과제입니다.\n\n"
        "_정직 고지: 1위 격차는 0.010(n=32)이며, 이 과제 자체는 최고 모델도 0.582 수준의 난제입니다._"
    )
    inp = gr.Textbox(lines=12, label="회의록", value=EXAMPLE)
    btn = gr.Button("결정사항 추출", variant="primary")
    out_table = gr.Markdown(label="추출 결과")
    out_raw = gr.Textbox(lines=6, label="모델 원문 출력")
    btn.click(extract, inputs=inp, outputs=[out_table, out_raw])
    gr.Markdown(
        "[벤치마크](https://github.com/palette-lab/palette-bench-ko) · "
        "[모델](https://huggingface.co/imcapsule/palette-k-midm) · "
        "[기술 보고서](https://pltt.xyz/paper) · Apache-2.0, base: KT Mi:dm-2.0 (MIT)"
    )

demo.launch()