update
parent
3851474aa3
commit
09f5be0180
|
|
@ -1,2 +1,3 @@
|
||||||
人与助手之间的语言交互默认为简体中文。
|
人与助手之间的语言交互默认为简体中文。
|
||||||
python 要使用 uv run 运行。
|
python 要使用 uv run 运行。
|
||||||
|
不要随意创建说明文档(比如 .md),除非用户有要求。
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
plaintiff:
|
||||||
|
- MO YUK PING
|
||||||
|
defendant:
|
||||||
|
- HONG KONG SPECIAL ADMINISTRATIVE REGION
|
||||||
|
jurisdiction_code: HKCFA
|
||||||
|
jurisdiction_name: Court of Final Appeal of the Hong Kong Special Administrative Region
|
||||||
|
case_location:
|
||||||
|
- 香港特別行政區
|
||||||
|
- Hong Kong Special Administrative Region
|
||||||
|
case_reason: >-
|
||||||
|
Applicant Mo Yuk Ping seeks leave to appeal against convictions for conspiracy to defraud and conspiracy
|
||||||
|
to pervert the course of public justice from CACC No. 26 of 2006.
|
||||||
|
case_object:
|
||||||
|
- leave to appeal
|
||||||
|
- conviction for conspiracy to defraud
|
||||||
|
- conviction for conspiracy to pervert the course of public justice
|
||||||
|
judgment_result:
|
||||||
|
- charge: Application for leave to appeal against conviction for conspiracy to pervert the course of public
|
||||||
|
justice under Charge 3 (liability issue)
|
||||||
|
result: Dismissed. Court of Appeal was right in refusing to certify points 2 to 5, no basis for leave
|
||||||
|
to appeal on 'substantial and grave injustice' ground, applicant does not have leave to appeal against
|
||||||
|
this conviction.
|
||||||
|
- charge: Application for leave to appeal against conviction for conspiracy to defraud under Charge 2
|
||||||
|
(liability issue)
|
||||||
|
result: Partially allowed. Time extended and leave to appeal granted, but limited to the certified point
|
||||||
|
on whether elements of conspiracy to defraud are sufficiently precise to satisfy constitutional requirement
|
||||||
|
of legal certainty. Court considered it appropriate to grant leave for pursuing this certified point.
|
||||||
|
judgment_summary: >-
|
||||||
|
申请人莫玉萍就串谋诈骗罪及串谋妨碍司法公正罪定罪申请上诉许可。上诉法院已就串谋诈骗罪构成要件是否符合法律确定性的宪法要求发出证明书。终审法院审查证据采纳规则、法官指示必要性及上诉法院对原审法官裁断的解读等争议点。法院认为上诉法院正确拒绝就第2至5点发出证明书,该等争议在案情脉络下不成立或属明显法律原则,不符合「重大严重不公」标准。最终批准就已发证明书的法律确定性问题延长时间并准予上诉许可,但驳回就妨碍司法公正罪定罪的上诉许可申请。
|
||||||
|
involved_entities:
|
||||||
|
- entity_name: Chief Justice Li
|
||||||
|
reason: Member of the Appeal Committee in this case, responsible for determining the application for
|
||||||
|
leave to appeal.
|
||||||
|
- entity_name: Mr Justice Bokhary PJ
|
||||||
|
reason: Presiding judge in this case, member of the Appeal Committee, authored the determination.
|
||||||
|
- entity_name: Mr Justice Chan PJ
|
||||||
|
reason: Member of the Appeal Committee in this case, responsible for determining the application for
|
||||||
|
leave to appeal.
|
||||||
|
- entity_name: Mo Yuk Ping
|
||||||
|
reason: Applicant in this criminal appeal case, convicted of conspiracy to defraud and conspiracy to
|
||||||
|
pervert the course of public justice.
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
plaintiff:
|
||||||
|
- MO YUK PING
|
||||||
|
defendant:
|
||||||
|
- HONG KONG SPECIAL ADMINISTRATIVE REGION
|
||||||
|
jurisdiction_code: HKCFA
|
||||||
|
jurisdiction_name: Court of Final Appeal of the Hong Kong Special Administrative Region
|
||||||
|
case_location:
|
||||||
|
- 香港特別行政區
|
||||||
|
- Hong Kong Special Administrative Region
|
||||||
|
case_reason: >-
|
||||||
|
Applicant seeks leave to appeal to the Court of Final Appeal against her convictions for conspiracy
|
||||||
|
to defraud and perverting the course of justice (CACC 26/2006).
|
||||||
|
case_object:
|
||||||
|
- criminal conviction
|
||||||
|
- constitutional right to legal certainty
|
||||||
|
- liberty
|
||||||
|
judgment_result:
|
||||||
|
- charge: Application for leave to appeal against conviction for conspiracy to defraud (Charge 2) (liability
|
||||||
|
issue)
|
||||||
|
result: Allowed. The Court granted leave to appeal limited to the certified point regarding whether
|
||||||
|
the elements of the offence of conspiracy to defraud are sufficiently precise to satisfy the constitutional
|
||||||
|
requirement of legal certainty.
|
||||||
|
- charge: Application for leave to appeal against conviction for conspiracy to pervert the course of public
|
||||||
|
justice (Charge 3) (liability issue)
|
||||||
|
result: Dismissed. The Court refused to certify the applicant's additional points (2 to 5) and found
|
||||||
|
no basis for leave to appeal on the 'substantial and grave injustice' ground, agreeing with the Court
|
||||||
|
of Appeal's reasons for refusal.
|
||||||
|
judgment_summary: >-
|
||||||
|
Applicant Mo Yuk Ping sought leave to appeal convictions for conspiracy to defraud and perverting justice.
|
||||||
|
The core issue was whether the fraud charge met constitutional requirements for legal certainty. The
|
||||||
|
Court accepted the certified point on legal certainty as a matter of great importance. However, it rejected
|
||||||
|
other points, finding the lower court's evidence assessment and factual findings were sound. Leave to
|
||||||
|
appeal was granted only for the certified point on Charge 2.
|
||||||
|
involved_entities:
|
||||||
|
- entity_name: Mo Yuk Ping
|
||||||
|
reason: The Applicant in this case, seeking leave to appeal against convictions for conspiracy to defraud
|
||||||
|
and conspiracy to pervert the course of public justice.
|
||||||
|
- entity_name: Hong Kong Special Administrative Region
|
||||||
|
reason: The Respondent in this case, representing the prosecution.
|
||||||
|
- entity_name: Chief Justice Li
|
||||||
|
reason: Member of the Appeal Committee presiding over the application for leave to appeal.
|
||||||
|
- entity_name: Mr Justice Bokhary PJ
|
||||||
|
reason: Member of the Appeal Committee and the judge who delivered the determination in this case.
|
||||||
|
- entity_name: Mr Justice Chan PJ
|
||||||
|
reason: Member of the Appeal Committee presiding over the application for leave to appeal.
|
||||||
|
- entity_name: Court of Appeal
|
||||||
|
reason: The lower court that certified one point of law but refused to certify others, whose judgment
|
||||||
|
is the subject of this leave application.
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
plaintiff:
|
||||||
|
- MO YUK PING
|
||||||
|
defendant:
|
||||||
|
- HONG KONG SPECIAL ADMINISTRATIVE REGION
|
||||||
|
jurisdiction_code: HKCFA
|
||||||
|
jurisdiction_name: Court of Final Appeal of the Hong Kong Special Administrative Region
|
||||||
|
case_location:
|
||||||
|
- 香港特別行政區
|
||||||
|
- Hong Kong Special Administrative Region
|
||||||
|
case_reason: >-
|
||||||
|
Plaintiff, a security guard, claims personal injury damages from defendant for assault at the mall in
|
||||||
|
July 2023.
|
||||||
|
case_object:
|
||||||
|
- personal injury damages
|
||||||
|
- medical expenses
|
||||||
|
- distress damages
|
||||||
|
judgment_result:
|
||||||
|
- charge: Conspiracy to defraud charge sufficiency (liability issue)
|
||||||
|
result: Allowed. Court granted leave to appeal on the certified point regarding whether the elements
|
||||||
|
of the offence of conspiracy to defraud are sufficiently precise to satisfy the constitutional requirement
|
||||||
|
of legal certainty. Court held the elements were not sufficiently precise and required further clarification.
|
||||||
|
reasons:
|
||||||
|
- The Court of Appeal certified the applicant's first point as raising a constitutional issue regarding
|
||||||
|
legal certainty
|
||||||
|
- The higher court found the elements of the offence were insufficiently defined
|
||||||
|
- The appeal was limited to this specific legal certainty issue
|
||||||
|
judgment_summary: >-
|
||||||
|
MO YUK PING sued the HKSAR for personal injury damages from a 2023 mall assault. Core issues centered
|
||||||
|
on liability and compensation for medical expenses and distress. The Court of Final Appeal certified
|
||||||
|
that the conspiracy to defraud charge's elements lacked legal certainty, allowing appeal on this point.
|
||||||
|
Other claims were dismissed as non-justiciable. Judgment granted leave to appeal on the legal certainty
|
||||||
|
issue, rejecting other points as moot or lacking merit.
|
||||||
|
involved_entities:
|
||||||
|
- entity_name: Chief Justice Li
|
||||||
|
reason: Presiding judge in this case, served as member of Appeal Committee responsible for adjudication.
|
||||||
|
- entity_name: Mr Justice Bokhary PJ
|
||||||
|
reason: Presiding judge in this case, served as member of Appeal Committee responsible for adjudication.
|
||||||
|
- entity_name: Mr Justice Chan PJ
|
||||||
|
reason: Presiding judge in this case, served as member of Appeal Committee responsible for adjudication.
|
||||||
|
- entity_name: HONG KONG SPECIAL ADMINISTRATIVE REGION
|
||||||
|
reason: Respondent in this case, representing the government entity involved in the legal proceedings.
|
||||||
|
|
@ -1,33 +1,33 @@
|
||||||
plaintiff:
|
plaintiff:
|
||||||
- HKSAR
|
- HKSAR
|
||||||
defendant:
|
defendant:
|
||||||
- MAK KWONG YIU (麥光耀)
|
- MAK KWONG YIU (麥光耀) (D1)
|
||||||
- CHAN LAI YEE (陳麗兒)
|
- CHAN LAI YEE (陳麗兒) (D2)
|
||||||
- WONG SHUK ON (黃淑安)
|
- WONG SHUK ON (黃淑安) (D3)
|
||||||
- LEE YICK MING (李易明)
|
- LEE YICK MING (李易明) (D4)
|
||||||
jurisdiction_code: HKCFA
|
jurisdiction_code: HKCFA
|
||||||
jurisdiction_name: Court of Final Appeal of the Hong Kong Special Administrative Region
|
jurisdiction_name: Court of Final Appeal of the Hong Kong Special Administrative Region
|
||||||
case_location:
|
case_location:
|
||||||
- 香港特別行政區
|
- 香港特別行政區
|
||||||
- Hong Kong Special Administrative Region
|
- Hong Kong Special Administrative Region
|
||||||
case_reason: >-
|
case_reason: >-
|
||||||
HKSAR appeals against the Court of Appeal's decision (CACC No. 239 of 2021) to overturn convictions
|
HKSAR appeals against the Court of Appeal's decision restoring the convictions of defendants in a conspiracy
|
||||||
of defendants for conspiracy to conceal CISL's role as placing agent in a connected transaction.
|
charge related to concealing CISL’s role as placing agent for CFHL, challenging the Court's
|
||||||
case_object:
|
case_object:
|
||||||
- conviction
|
- convictions
|
||||||
- right to have conviction upheld
|
|
||||||
- connected transaction determination
|
|
||||||
judgment_result:
|
judgment_result:
|
||||||
- charge: Conspiracy to conceal CISL's role as placing agent (liability issue)
|
- charge: Conspiracy charges (liability issue)
|
||||||
result: Upheld. Appeal allowed, convictions restored. Court found concealment of CISL's agency constituted
|
result: Allowed. The Court agreed that the defendants' scheme involved concealing CISL's role as the
|
||||||
unlawful connected transaction under Listing Rules, and directors' conflict of interest was central
|
actual placing agent, which was a connected transaction under the Listing Rules.
|
||||||
to conspiracy charges.
|
- charge: Interposition of Gransing being a mere disguise (quantum issue)
|
||||||
|
result: Partially allowed. While the Court agreed that the interposition of Gransing was an arrangement
|
||||||
|
to conceal CISL's role, it did not find that this alone was sufficient to establish the conspiracy
|
||||||
|
charges.
|
||||||
judgment_summary: >-
|
judgment_summary: >-
|
||||||
HKSAR appeals against the Court of Appeal's overturning of convictions for conspiracy to conceal CISL's
|
The case involves HKSAR appealing against convictions for conspiracy charges related to concealing CISL's
|
||||||
role in a connected transaction. Core issues: upholding convictions and determining connected transaction
|
role in a placing agent transaction. The Court upheld that the scheme involved concealing CISL’s role,
|
||||||
status. Court rejected narrow 'sham' test from Snook v London, citing Adams v The Queen, finding concealment
|
but partially allowed the appeal by rejecting the sole reliance on interposition as sufficient evidence
|
||||||
of CISL's agency constituted unlawful connected transaction under Listing Rules. Convictions upheld,
|
of conspiracy. Key laws and precedents cited include Adams v The Queen and Mo Yuk Ping v HKSAR.
|
||||||
appeal allowed, with directors' conflicts central to charges. Hong Kong Stock Ex
|
|
||||||
involved_entities:
|
involved_entities:
|
||||||
- entity_name: Mr Justice Ribeiro PJ
|
- entity_name: Mr Justice Ribeiro PJ
|
||||||
reason: Presiding judge in this case, responsible for fact-finding and adjudication.
|
reason: Presiding judge in this case, responsible for fact-finding and adjudication.
|
||||||
|
|
@ -39,8 +39,13 @@ involved_entities:
|
||||||
reason: Presiding judge in this case, responsible for fact-finding and adjudication.
|
reason: Presiding judge in this case, responsible for fact-finding and adjudication.
|
||||||
- entity_name: Sir William Young NPJ
|
- entity_name: Sir William Young NPJ
|
||||||
reason: Presiding judge in this case, responsible for fact-finding and adjudication.
|
reason: Presiding judge in this case, responsible for fact-finding and adjudication.
|
||||||
- entity_name: Diplock LJ
|
- entity_name: HKSAR (Appellant)
|
||||||
reason: Served as judge in Snook v London and West Riding Investments Ltd, articulated test for determining
|
reason: Government department involved as the appellant in the case.
|
||||||
sham transactions.
|
- entity_name: MAK KWONG YIU (麥光耀) (D1)
|
||||||
- entity_name: Hong Kong Stock Exchange
|
reason: Respondent in the case.
|
||||||
reason: Institution involved in regulatory framework for connected transactions.
|
- entity_name: CHAN LAI YEE (陳麗兒) (D2)
|
||||||
|
reason: Respondent in the case.
|
||||||
|
- entity_name: WONG SHUK ON (黃淑安) (D3)
|
||||||
|
reason: Respondent in the case.
|
||||||
|
- entity_name: LEE YICK MING (李易明) (D4)
|
||||||
|
reason: Respondent in the case.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
plaintiff:
|
||||||
|
- HKSAR
|
||||||
|
defendant:
|
||||||
|
- MAK KWONG YIU (麥光耀) (D1)
|
||||||
|
- CHAN LAI YEE (陳麗兒) (D2)
|
||||||
|
- WONG SHUK ON (黃淑安) (D3)
|
||||||
|
- LEE YICK MING (李易明) (D4)
|
||||||
|
jurisdiction_code: HKCFA
|
||||||
|
jurisdiction_name: Court of Final Appeal of the Hong Kong Special Administrative Region
|
||||||
|
case_location:
|
||||||
|
- 香港特別行政區
|
||||||
|
- Hong Kong Special Administrative Region
|
||||||
|
case_reason: >-
|
||||||
|
HKSAR appeals against the Court of Appeal's decision restoring the convictions of defendants in a conspiracy
|
||||||
|
charge related to concealing CISL’s role as placing agent for CFHL, challenging the Court's
|
||||||
|
case_object:
|
||||||
|
- convictions
|
||||||
|
judgment_result:
|
||||||
|
- charge: Conspiracy charges (liability issue)
|
||||||
|
result: Allowed. The Court agreed that the defendants' scheme involved concealing CISL's role as the
|
||||||
|
actual placing agent, which was a connected transaction under the Listing Rules.
|
||||||
|
- charge: Interposition of Gransing being a mere disguise (quantum issue)
|
||||||
|
result: Partially allowed. While the Court agreed that the interposition of Gransing was an arrangement
|
||||||
|
to conceal CISL's role, it did not find that this alone was sufficient to establish the conspiracy
|
||||||
|
charges.
|
||||||
|
judgment_summary: >-
|
||||||
|
The case involves HKSAR appealing against convictions for conspiracy charges related to concealing CISL's
|
||||||
|
role in a placing agent transaction. The Court upheld that the scheme involved concealing CISL’s role,
|
||||||
|
but partially allowed the appeal by rejecting the sole reliance on interposition as sufficient evidence
|
||||||
|
of conspiracy. Key laws and precedents cited include Adams v The Queen and Mo Yuk Ping v HKSAR.
|
||||||
|
involved_entities:
|
||||||
|
- entity_name: Mr Justice Ribeiro PJ
|
||||||
|
reason: Presiding judge in this case, responsible for fact-finding and adjudication.
|
||||||
|
- entity_name: Mr Justice Fok PJ
|
||||||
|
reason: Presiding judge in this case, responsible for fact-finding and adjudication.
|
||||||
|
- entity_name: Mr Justice Lam PJ
|
||||||
|
reason: Presiding judge in this case, responsible for fact-finding and adjudication.
|
||||||
|
- entity_name: Mr Justice Stock NPJ
|
||||||
|
reason: Presiding judge in this case, responsible for fact-finding and adjudication.
|
||||||
|
- entity_name: Sir William Young NPJ
|
||||||
|
reason: Presiding judge in this case, responsible for fact-finding and adjudication.
|
||||||
|
- entity_name: HKSAR (Appellant)
|
||||||
|
reason: Government department involved as the appellant in the case.
|
||||||
|
- entity_name: MAK KWONG YIU (麥光耀) (D1)
|
||||||
|
reason: Respondent in the case.
|
||||||
|
- entity_name: CHAN LAI YEE (陳麗兒) (D2)
|
||||||
|
reason: Respondent in the case.
|
||||||
|
- entity_name: WONG SHUK ON (黃淑安) (D3)
|
||||||
|
reason: Respondent in the case.
|
||||||
|
- entity_name: LEE YICK MING (李易明) (D4)
|
||||||
|
reason: Respondent in the case.
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
plaintiff:
|
||||||
|
- HKSAR
|
||||||
|
defendant:
|
||||||
|
- MAK KWONG YIU (麥光耀)
|
||||||
|
- CHAN LAI YEE (陳麗兒)
|
||||||
|
- WONG SHUK ON (黃淑安)
|
||||||
|
- LEE YICK MING (李易明)
|
||||||
|
jurisdiction_code: HKCFA
|
||||||
|
jurisdiction_name: Court of Final Appeal of the Hong Kong Special Administrative Region
|
||||||
|
case_location:
|
||||||
|
- 香港特別行政區
|
||||||
|
- Hong Kong Special Administrative Region
|
||||||
|
case_reason: >-
|
||||||
|
HKSAR appeals against the Court of Appeal's decision (CACC No. 239 of 2021) to overturn convictions
|
||||||
|
of defendants for conspiracy to conceal CISL's role as placing agent in a connected transaction.
|
||||||
|
case_object:
|
||||||
|
- conviction
|
||||||
|
- right to have conviction upheld
|
||||||
|
- connected transaction determination
|
||||||
|
judgment_result:
|
||||||
|
- charge: Conspiracy to conceal CISL's role as placing agent (liability issue)
|
||||||
|
result: Upheld. Appeal allowed, convictions restored. Court found concealment of CISL's agency constituted
|
||||||
|
unlawful connected transaction under Listing Rules, and directors' conflict of interest was central
|
||||||
|
to conspiracy charges.
|
||||||
|
judgment_summary: >-
|
||||||
|
HKSAR appeals against the Court of Appeal's overturning of convictions for conspiracy to conceal CISL's
|
||||||
|
role in a connected transaction. Core issues: upholding convictions and determining connected transaction
|
||||||
|
status. Court rejected narrow 'sham' test from Snook v London, citing Adams v The Queen, finding concealment
|
||||||
|
of CISL's agency constituted unlawful connected transaction under Listing Rules. Convictions upheld,
|
||||||
|
appeal allowed, with directors' conflicts central to charges. Hong Kong Stock Ex
|
||||||
|
involved_entities:
|
||||||
|
- entity_name: Mr Justice Ribeiro PJ
|
||||||
|
reason: Presiding judge in this case, responsible for fact-finding and adjudication.
|
||||||
|
- entity_name: Mr Justice Fok PJ
|
||||||
|
reason: Presiding judge in this case, responsible for fact-finding and adjudication.
|
||||||
|
- entity_name: Mr Justice Lam PJ
|
||||||
|
reason: Presiding judge in this case, responsible for fact-finding and adjudication.
|
||||||
|
- entity_name: Mr Justice Stock NPJ
|
||||||
|
reason: Presiding judge in this case, responsible for fact-finding and adjudication.
|
||||||
|
- entity_name: Sir William Young NPJ
|
||||||
|
reason: Presiding judge in this case, responsible for fact-finding and adjudication.
|
||||||
|
- entity_name: Diplock LJ
|
||||||
|
reason: Served as judge in Snook v London and West Riding Investments Ltd, articulated test for determining
|
||||||
|
sham transactions.
|
||||||
|
- entity_name: Hong Kong Stock Exchange
|
||||||
|
reason: Institution involved in regulatory framework for connected transactions.
|
||||||
|
|
@ -41,14 +41,24 @@ hk_case_extractor.py
|
||||||
依賴
|
依賴
|
||||||
----
|
----
|
||||||
pip install requests pyyaml
|
pip install requests pyyaml
|
||||||
本地需運行:ollama serve
|
|
||||||
模型:ollama pull qwen2.5:7b-instruct (推薦,中文抽取甜點)
|
|
||||||
或 ollama pull glm4:9b
|
|
||||||
|
|
||||||
使用
|
使用
|
||||||
----
|
----
|
||||||
python hk_case_extractor.py <input.txt>
|
# 使用本地 Ollama(默認)
|
||||||
|
python hk_case_extractor.py case.txt
|
||||||
python hk_case_extractor.py case.txt --model qwen2.5:7b-instruct --out result.yaml
|
python hk_case_extractor.py case.txt --model qwen2.5:7b-instruct --out result.yaml
|
||||||
|
|
||||||
|
# 使用 OpenRouter
|
||||||
|
python hk_case_extractor.py case.txt \\
|
||||||
|
--base-url https://openrouter.ai/api/v1 \\
|
||||||
|
--model anthropic/claude-3.5-sonnet \\
|
||||||
|
--api-key your-api-key
|
||||||
|
|
||||||
|
# 使用 OpenAI
|
||||||
|
python hk_case_extractor.py case.txt \\
|
||||||
|
--base-url https://api.openai.com/v1 \\
|
||||||
|
--model gpt-4 \\
|
||||||
|
--api-key your-api-key
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
@ -69,8 +79,9 @@ import yaml
|
||||||
# 配置
|
# 配置
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
OLLAMA_URL = "https://openai.iconsz.com/ollama3090/api/chat"
|
DEFAULT_BASE_URL = "http://localhost:11434/v1" # Ollama 默認 OpenAI 兼容端點
|
||||||
DEFAULT_MODEL = "qwen2.5:7b-instruct"
|
DEFAULT_MODEL = "qwen2.5:7b-instruct"
|
||||||
|
DEFAULT_API_KEY = "ollama" # Ollama 不需要真實 key,但 API 需要提供
|
||||||
DEFAULT_TIMEOUT = 240
|
DEFAULT_TIMEOUT = 240
|
||||||
MAX_RETRIES = 2
|
MAX_RETRIES = 2
|
||||||
|
|
||||||
|
|
@ -406,35 +417,60 @@ def gather_all(text: str) -> dict[str, str]:
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 2. Ollama 客戶端:JSON Schema 強制 + 重試
|
# 2. OpenAI 兼容客戶端:支持 Ollama / OpenRouter / OpenAI 等
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class OllamaClient:
|
class OpenAICompatibleClient:
|
||||||
|
"""OpenAI 兼容的 API 客戶端
|
||||||
|
|
||||||
|
支持:
|
||||||
|
- Ollama (http://localhost:11434/v1)
|
||||||
|
- OpenRouter (https://openrouter.ai/api/v1)
|
||||||
|
- OpenAI (https://api.openai.com/v1)
|
||||||
|
- 其他 OpenAI 兼容的服務
|
||||||
|
"""
|
||||||
model: str = DEFAULT_MODEL
|
model: str = DEFAULT_MODEL
|
||||||
url: str = OLLAMA_URL
|
base_url: str = DEFAULT_BASE_URL
|
||||||
|
api_key: str = DEFAULT_API_KEY
|
||||||
timeout: int = DEFAULT_TIMEOUT
|
timeout: int = DEFAULT_TIMEOUT
|
||||||
|
|
||||||
def chat_json(self, system: str, user: str, schema: dict,
|
def chat_json(self, system: str, user: str, schema: dict,
|
||||||
temperature: float = 0.0,
|
temperature: float = 0.0,
|
||||||
num_ctx: int = 8192) -> dict:
|
max_tokens: int = 4096) -> dict:
|
||||||
"""調用 Ollama,使用 format=<JSON Schema> 強制結構化輸出"""
|
"""調用 OpenAI 兼容 API,使用 response_format 強制 JSON 輸出"""
|
||||||
|
# 構建請求 URL
|
||||||
|
url = f"{self.base_url.rstrip('/')}/chat/completions"
|
||||||
|
|
||||||
|
# 構建請求頭
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": f"Bearer {self.api_key}",
|
||||||
|
}
|
||||||
|
|
||||||
|
# 構建請求體
|
||||||
payload = {
|
payload = {
|
||||||
"model": self.model,
|
"model": self.model,
|
||||||
"messages": [
|
"messages": [
|
||||||
{"role": "system", "content": system},
|
{"role": "system", "content": system},
|
||||||
{"role": "user", "content": user},
|
{"role": "user", "content": user},
|
||||||
],
|
],
|
||||||
"format": schema,
|
"temperature": temperature,
|
||||||
"stream": False,
|
"max_tokens": max_tokens,
|
||||||
"options": {"temperature": temperature, "num_ctx": num_ctx},
|
"response_format": {"type": "json_object"}, # OpenAI 兼容的 JSON 模式
|
||||||
}
|
}
|
||||||
r = requests.post(self.url, json=payload, timeout=self.timeout)
|
|
||||||
|
# 發送請求
|
||||||
|
r = requests.post(url, json=payload, headers=headers, timeout=self.timeout)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
content = r.json()["message"]["content"]
|
|
||||||
|
# 解析響應
|
||||||
|
response_data = r.json()
|
||||||
|
content = response_data["choices"][0]["message"]["content"]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return json.loads(content)
|
return json.loads(content)
|
||||||
except json.JSONDecodeError as e:
|
except json.JSONDecodeError:
|
||||||
# 嘗試剝離可能的 ```json fence
|
# 嘗試剝離可能的 ```json fence
|
||||||
stripped = re.sub(r"^```(?:json)?\s*|\s*```$", "",
|
stripped = re.sub(r"^```(?:json)?\s*|\s*```$", "",
|
||||||
content.strip(), flags=re.S)
|
content.strip(), flags=re.S)
|
||||||
|
|
@ -551,7 +587,7 @@ Output:
|
||||||
{"plaintiff":["MO YUK PING"],"defendant":["HONG KONG SPECIAL ADMINISTRATIVE REGION"]}"""
|
{"plaintiff":["MO YUK PING"],"defendant":["HONG KONG SPECIAL ADMINISTRATIVE REGION"]}"""
|
||||||
|
|
||||||
|
|
||||||
def extract_parties(client: OllamaClient, context: str, lang: str = 'zh') -> dict:
|
def extract_parties(client: OpenAICompatibleClient, context: str, lang: str = 'zh') -> dict:
|
||||||
system = PARTIES_SYSTEM_ZH if lang == 'zh' else PARTIES_SYSTEM_EN
|
system = PARTIES_SYSTEM_ZH if lang == 'zh' else PARTIES_SYSTEM_EN
|
||||||
fewshot = PARTIES_FEWSHOT_ZH if lang == 'zh' else PARTIES_FEWSHOT_EN
|
fewshot = PARTIES_FEWSHOT_ZH if lang == 'zh' else PARTIES_FEWSHOT_EN
|
||||||
|
|
||||||
|
|
@ -652,7 +688,7 @@ def _reason_object_validator(out: dict, lang: str = 'zh') -> tuple[bool, str]:
|
||||||
return True, ""
|
return True, ""
|
||||||
|
|
||||||
|
|
||||||
def extract_reason_object(client: OllamaClient, context: str, lang: str = 'zh') -> dict:
|
def extract_reason_object(client: OpenAICompatibleClient, context: str, lang: str = 'zh') -> dict:
|
||||||
system = REASON_OBJECT_SYSTEM_ZH if lang == 'zh' else REASON_OBJECT_SYSTEM_EN
|
system = REASON_OBJECT_SYSTEM_ZH if lang == 'zh' else REASON_OBJECT_SYSTEM_EN
|
||||||
fewshot = REASON_OBJECT_FEWSHOT_ZH if lang == 'zh' else REASON_OBJECT_FEWSHOT_EN
|
fewshot = REASON_OBJECT_FEWSHOT_ZH if lang == 'zh' else REASON_OBJECT_FEWSHOT_EN
|
||||||
schema = get_reason_object_schema(lang)
|
schema = get_reason_object_schema(lang)
|
||||||
|
|
@ -770,7 +806,7 @@ def _judgment_validator(out: dict, lang: str = 'zh') -> tuple[bool, str]:
|
||||||
return True, ""
|
return True, ""
|
||||||
|
|
||||||
|
|
||||||
def extract_judgment_result(client: OllamaClient, context: str, lang: str = 'zh') -> dict:
|
def extract_judgment_result(client: OpenAICompatibleClient, context: str, lang: str = 'zh') -> dict:
|
||||||
system = JUDGMENT_RESULT_SYSTEM_ZH if lang == 'zh' else JUDGMENT_RESULT_SYSTEM_EN
|
system = JUDGMENT_RESULT_SYSTEM_ZH if lang == 'zh' else JUDGMENT_RESULT_SYSTEM_EN
|
||||||
fewshot = JUDGMENT_RESULT_FEWSHOT_ZH if lang == 'zh' else JUDGMENT_RESULT_FEWSHOT_EN
|
fewshot = JUDGMENT_RESULT_FEWSHOT_ZH if lang == 'zh' else JUDGMENT_RESULT_FEWSHOT_EN
|
||||||
|
|
||||||
|
|
@ -884,7 +920,7 @@ def _entities_validator(out: dict, lang: str = 'zh') -> tuple[bool, str]:
|
||||||
return True, ""
|
return True, ""
|
||||||
|
|
||||||
|
|
||||||
def extract_entities(client: OllamaClient, context: str, lang: str = 'zh') -> dict:
|
def extract_entities(client: OpenAICompatibleClient, context: str, lang: str = 'zh') -> dict:
|
||||||
system = ENTITIES_SYSTEM_ZH if lang == 'zh' else ENTITIES_SYSTEM_EN
|
system = ENTITIES_SYSTEM_ZH if lang == 'zh' else ENTITIES_SYSTEM_EN
|
||||||
fewshot = ENTITIES_FEWSHOT_ZH if lang == 'zh' else ENTITIES_FEWSHOT_EN
|
fewshot = ENTITIES_FEWSHOT_ZH if lang == 'zh' else ENTITIES_FEWSHOT_EN
|
||||||
|
|
||||||
|
|
@ -962,7 +998,7 @@ def _summary_validator(out: dict, lang: str = 'zh') -> tuple[bool, str]:
|
||||||
return True, ""
|
return True, ""
|
||||||
|
|
||||||
|
|
||||||
def extract_summary(client: OllamaClient,
|
def extract_summary(client: OpenAICompatibleClient,
|
||||||
prior: dict, analysis: str, lang: str = 'zh') -> dict:
|
prior: dict, analysis: str, lang: str = 'zh') -> dict:
|
||||||
system = SUMMARY_SYSTEM_ZH if lang == 'zh' else SUMMARY_SYSTEM_EN
|
system = SUMMARY_SYSTEM_ZH if lang == 'zh' else SUMMARY_SYSTEM_EN
|
||||||
schema = get_summary_schema(lang)
|
schema = get_summary_schema(lang)
|
||||||
|
|
@ -1072,7 +1108,7 @@ def validate_and_fix(result: dict, lang: str = 'zh') -> tuple[dict, list[str]]:
|
||||||
# 5. 主管線
|
# 5. 主管線
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
def run_pipeline(text: str, model: str) -> dict:
|
def run_pipeline(text: str, model: str, base_url: str, api_key: str) -> dict:
|
||||||
log = lambda m: print(m, file=sys.stderr)
|
log = lambda m: print(m, file=sys.stderr)
|
||||||
|
|
||||||
log("[0/7] 檢測語言...")
|
log("[0/7] 檢測語言...")
|
||||||
|
|
@ -1091,7 +1127,7 @@ def run_pipeline(text: str, model: str) -> dict:
|
||||||
hits_info = f"hits={ctx[f'_{g}_hits']}" if ctx[f'_{g}_hits'] != "0" else "直接截取"
|
hits_info = f"hits={ctx[f'_{g}_hits']}" if ctx[f'_{g}_hits'] != "0" else "直接截取"
|
||||||
log(f" {g:16s} len={len(ctx[g]):5d} {hits_info}")
|
log(f" {g:16s} len={len(ctx[g]):5d} {hits_info}")
|
||||||
|
|
||||||
client = OllamaClient(model=model)
|
client = OpenAICompatibleClient(model=model, base_url=base_url, api_key=api_key)
|
||||||
|
|
||||||
log("[2/7] 抽取當事人...")
|
log("[2/7] 抽取當事人...")
|
||||||
parties = extract_parties(client, ctx["parties"], lang)
|
parties = extract_parties(client, ctx["parties"], lang)
|
||||||
|
|
@ -1176,9 +1212,33 @@ def to_yaml(result: dict) -> str:
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
ap = argparse.ArgumentParser(
|
ap = argparse.ArgumentParser(
|
||||||
description="香港判決書結構化抽取(本地 Ollama 版)")
|
description="香港判決書結構化抽取(OpenAI 兼容 API)",
|
||||||
|
epilog="""
|
||||||
|
示例用法:
|
||||||
|
# 使用本地 Ollama
|
||||||
|
python hk_case_extractor.py case.txt --model qwen2.5:7b-instruct
|
||||||
|
|
||||||
|
# 使用 OpenRouter
|
||||||
|
python hk_case_extractor.py case.txt \\
|
||||||
|
--base-url https://openrouter.ai/api/v1 \\
|
||||||
|
--model anthropic/claude-3.5-sonnet \\
|
||||||
|
--api-key your-api-key
|
||||||
|
|
||||||
|
# 使用 OpenAI
|
||||||
|
python hk_case_extractor.py case.txt \\
|
||||||
|
--base-url https://api.openai.com/v1 \\
|
||||||
|
--model gpt-4 \\
|
||||||
|
--api-key your-api-key
|
||||||
|
""",
|
||||||
|
formatter_class=argparse.RawDescriptionHelpFormatter
|
||||||
|
)
|
||||||
ap.add_argument("input", help="判決書文本路徑(.txt 或 .json)")
|
ap.add_argument("input", help="判決書文本路徑(.txt 或 .json)")
|
||||||
ap.add_argument("--model", default=DEFAULT_MODEL, help="Ollama 模型名")
|
ap.add_argument("--model", default=DEFAULT_MODEL,
|
||||||
|
help=f"模型名稱(默認:{DEFAULT_MODEL})")
|
||||||
|
ap.add_argument("--base-url", default=DEFAULT_BASE_URL,
|
||||||
|
help=f"API base URL(默認:{DEFAULT_BASE_URL})")
|
||||||
|
ap.add_argument("--api-key", default=DEFAULT_API_KEY,
|
||||||
|
help="API key(Ollama 可忽略)")
|
||||||
ap.add_argument("--out", default=None, help="輸出 YAML 路徑(默認 stdout)")
|
ap.add_argument("--out", default=None, help="輸出 YAML 路徑(默認 stdout)")
|
||||||
ap.add_argument("--debug-dump", default=None,
|
ap.add_argument("--debug-dump", default=None,
|
||||||
help="額外輸出原始 JSON 結果到該路徑(便於 diff)")
|
help="額外輸出原始 JSON 結果到該路徑(便於 diff)")
|
||||||
|
|
@ -1196,7 +1256,7 @@ def main() -> None:
|
||||||
else:
|
else:
|
||||||
text = input_path.read_text(encoding="utf-8")
|
text = input_path.read_text(encoding="utf-8")
|
||||||
|
|
||||||
result = run_pipeline(text, args.model)
|
result = run_pipeline(text, args.model, args.base_url, args.api_key)
|
||||||
|
|
||||||
if args.debug_dump:
|
if args.debug_dump:
|
||||||
Path(args.debug_dump).write_text(
|
Path(args.debug_dump).write_text(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue