news 2026/8/2 6:40:44

基于Gemini大模型构建新闻结构化信息抽取系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Gemini大模型构建新闻结构化信息抽取系统

1. 项目概述:当新闻报道遇见结构化数据

最近在折腾一个挺有意思的小项目,我把它叫做“Groundsource”。核心想法很简单:我们每天被海量的新闻资讯淹没,但这些信息大多是“非结构化”的文本。能不能用一种更聪明的方式,把这些散落在各处的新闻报道,自动提炼、整合成结构化的数据,比如事件时间线、涉及的关键人物与组织、地点、核心观点,甚至是情感倾向?这听起来像是给新闻装上一个“数据引擎”。

这个想法的落地,离不开一个强大的“大脑”来理解文本。我选择了Google的Gemini模型作为这个项目的核心驱动。Gemini在多模态理解和复杂推理任务上展现出的能力,让它成为处理新闻报道这种富含上下文、隐含信息和复杂逻辑内容的理想选择。Groundsource不是一个简单的关键词提取工具,它的目标是理解新闻的“故事线”,并从中抽取出有分析价值的数据骨架。

这个项目适合谁呢?如果你是数据分析师、市场研究员、政策分析者,或者任何需要从公开信息中快速洞察趋势的人,Groundsource的思路或许能给你带来启发。它本质上是一个“信息减噪”和“结构转化”的管道,把嘈杂的文本输入,变成干净、可查询、可分析的数据输出。接下来,我就详细拆解一下我是如何构思并实现这个项目的,包括背后的考量、具体的实现步骤,以及一路走来踩过的那些坑。

2. 核心思路与架构设计

2.1 为什么是“从新闻到数据”?

新闻报道是现实世界的映射,但它的形式是线性的、叙述性的。我们读一篇关于某公司发布新产品的报道,里面会混杂着产品特性、市场反应、股价波动、高管言论、竞争对手动态等多种信息。人工梳理费时费力,且难以规模化。而结构化的数据,比如一个包含[时间, 实体, 动作, 属性, 来源]的记录,则可以被数据库存储、被脚本分析、被可视化工具呈现。

Groundsource的目标就是搭建这个转换桥梁。其核心价值在于:

  1. 自动化:替代人工阅读和标注,处理速度提升几个数量级。
  2. 一致性:基于同一套规则(即模型的理解能力)提取信息,减少主观偏差。
  3. 可追溯:每条生成的数据都能关联回原始新闻的片段,保证了数据的可解释性。
  4. 可拓展:一旦管道建成,可以很容易地接入不同的新闻源(RSS、API、爬虫),进行批量处理。

2.2 技术选型:为何锁定Gemini?

在项目启动前,我评估了几种主流的大语言模型方案。最终选择Gemini,是基于以下几个关键考量:

  • 强大的上下文理解与推理能力:新闻报道常有弦外之音、讽刺或间接引用。Gemini在复杂语境下的表现,对于准确识别事件间的因果关系、人物的真实立场至关重要。例如,它能较好地区分“某公司‘声称’业绩增长”和“财报‘显示’业绩增长”之间的微妙差别。
  • 对长文本的友好支持:Gemini 1.5 Pro版本支持巨大的上下文窗口(可达百万token)。这意味着我可以将多篇相关的、时间跨度较长的新闻报道一次性喂给模型,让它进行跨文档的分析和综合,构建更完整的事件图谱,而不是孤立地分析单篇文章。
  • 可控的输出与函数调用:通过精心设计的提示词,我可以引导Gemini以严格指定的JSON格式输出结果。这比让模型自由发挥生成文本,再费力地用正则表达式去解析要可靠得多。结构化输出是数据管道稳定性的基石。
  • API的易用性与性价比:相较于需要复杂自部署的方案,Gemini API提供了清晰、稳定的接口。其按使用量计费的模式,对于我这种间歇性、探索性的项目初期来说,成本更可控,也免去了运维的烦恼。

注意:模型选型没有银弹。如果你的场景对实时性要求极高、或需要完全离线部署,可能需要考虑量化后的小模型或本地部署方案。但就Groundsource追求深度理解和分析能力的首要目标而言,Gemini是目前综合权衡下的优选。

2.3 系统架构总览

Groundsource的架构可以看作一个数据处理流水线,分为四个主要阶段:

新闻源 (RSS/API/文件) -> 文本预处理 -> Gemini 理解与抽取 -> 数据后处理与存储
  1. 采集层:负责从各种渠道获取原始新闻文本。这部分相对独立,可以根据需要适配不同的输入源。
  2. 预处理层:对原始文本进行清洗。包括去除HTML标签、广告、无关的页眉页脚、规范化编码等。一个干净的输入文本能显著提升后续模型理解的准确性。
  3. 核心处理层:这是Groundsource的“心脏”。它将预处理后的文本,连同我精心设计的“提示词”,发送给Gemini API。提示词的任务是“指挥”Gemini按照我们设定的数据模式进行信息抽取。
  4. 后处理与存储层:接收Gemini返回的结构化数据(通常是JSON),进行验证、去重、关联,然后存入数据库(如SQLite、PostgreSQL)或数据仓库,供后续分析使用。

3. 核心实现:提示词工程与数据建模

3.1 设计“数据抽取蓝图”

在调用Gemini之前,我必须先想清楚:我希望从一篇新闻里抽出什么样的数据?这直接决定了提示词怎么写,以及后端数据表如何设计。

经过对多种类型新闻(科技、财经、社会)的分析,我定义了一套核心数据实体:

  • 事件:新闻报道的核心事实。例如,“发布新产品”、“召开财报会议”、“达成战略合作”。
  • 实体:参与事件的“角色”。包括人物(CEO、发言人)、组织(公司、政府机构)、地点(城市、国家)、产品等。
  • 关系:连接实体和事件的纽带。例如,“人物A属于组织B”,“事件C发生在地点D”,“组织E发布了产品F”。
  • 属性:描述实体或事件的细节。例如,事件的“发生时间”(精确到日),产品的“价格”,公司股价的“涨跌幅”。
  • 情感/倾向:对事件或实体所表达的观点倾向(积极/消极/中性)。这通常从形容词和上下文推断。
  • 引用源:记录该条信息出自原文的哪一段落,便于溯源。

基于此,我设计了一个目标JSON Schema来指导Gemini的输出。这个Schema就是给模型的“答题卡”。

3.2 构建高效的提示词

提示词是与Gemini沟通的“语言”。一个糟糕的提示词会得到混乱的结果,而一个好的提示词能让模型变成精准的信息提取专家。我的提示词结构如下:

你是一个专业的新闻数据分析助手。你的任务是从以下新闻报道中,提取结构化的信息。 请严格按照以下JSON格式输出,不要添加任何额外的解释。 { "summary": "新闻的简要概述(1-2句话)", "events": [ { "description": "事件描述", "date": "YYYY-MM-DD格式的日期,如果原文未明确则留空", "type": "事件类型,如:产品发布、财报公布、并购、政策变更等" } ], "entities": [ { "name": "实体名称", "type": "类型,如:Person, Organization, Location, Product", "role_in_news": "在本文中的角色或提及的上下文" } ], "relationships": [ { "from_entity": "发起方实体名称", "to_entity": "接收方实体名称或事件描述", "relation": "关系类型,如:employed_by, located_in, announced, criticized" } ], "key_attributes": [ { "target": "所属实体或事件", "attribute_name": "属性名,如:stock_price_change, product_price, user_count", "value": "属性值", "unit": "单位(如适用)" } ], "sentiment_analysis": { "overall_tone": "整体基调", "key_points": [ {"aspect": "方面", "sentiment": "情感倾向", "evidence_snippet": "原文片段"} ] }, "source_references": [ {"info": "被提取的信息点", "text_snippet": "对应的原文片段"} ] } 新闻报道内容: """ {这里插入预处理后的新闻文本} """

提示词设计的几个关键技巧:

  1. 角色设定:开头明确模型角色,让它进入状态。
  2. 指令清晰:“严格按JSON格式输出,不要额外解释”是黄金指令,能极大减少无效输出。
  3. 结构化示例:提供详细的JSON结构,相当于给了模型一个模板。字段名和预期的值类型要明确。
  4. 字段解释:对容易混淆的字段(如type,relation)给出可选值示例,引导模型从有限集合中选择,提高一致性。
  5. 包含原文:要求模型在source_referencesevidence_snippet中引用原文片段。这不仅是溯源的需要,更是验证模型抽取是否准确的重要依据。如果模型“编造”了信息,你很容易通过核对原文发现。

3.3 与Gemini API的交互实现

有了提示词,接下来就是用代码调用Gemini API。我使用Python的google-generativeai库,过程很直接。

import google.generativeai as genai import json # 1. 配置API密钥(务必从环境变量读取,不要硬编码) genai.configure(api_key=os.environ.get("GEMINI_API_KEY")) # 2. 选择模型(我主要用gemini-1.5-pro,平衡能力与成本) model = genai.GenerativeModel('gemini-1.5-pro') # 3. 构建提示词 def build_prompt(news_text): system_instruction = """你是一个专业的新闻数据分析助手...""" # 完整的提示词如上节 full_prompt = system_instruction + f"\n\n新闻报道内容:\n\"\"\"{news_text}\"\"\"" return full_prompt # 4. 调用并解析响应 def extract_structured_data(news_text): prompt = build_prompt(news_text) try: # 设置生成配置,控制输出 generation_config = { "temperature": 0.1, # 低温度,确保输出稳定、确定性高 "top_p": 0.8, "top_k": 40, "max_output_tokens": 2048, # 根据输出复杂度调整 } response = model.generate_content(prompt, generation_config=generation_config) # 提取响应文本 response_text = response.text # 尝试解析JSON,Gemini有时会在JSON外包裹markdown代码块标记 if response_text.startswith('```json'): response_text = response_text[7:-3] # 去除 ```json 和 ``` elif response_text.startswith('```'): response_text = response_text[3:-3] # 去除 ``` 和 ``` structured_data = json.loads(response_text.strip()) return structured_data except json.JSONDecodeError as e: print(f"JSON解析失败: {e}") print(f"原始响应: {response_text}") # 这里可以加入重试或更复杂的清洗逻辑 return None except Exception as e: print(f"API调用异常: {e}") return None

关键参数解析:

  • temperature:设置为较低的0.1-0.3。在信息抽取任务中,我们需要的是准确、一致的输出,而不是创造性。低温度值能减少模型的随机性。
  • max_output_tokens:需要根据你定义的JSON Schema的复杂程度来预估。太短会导致输出被截断,太长则浪费资源。可以先测试几篇,观察输出长度,再设定一个安全裕量。

4. 数据处理管道与工程化实践

4.1 文本预处理:为模型准备“干净食材”

“垃圾进,垃圾出”在AI领域同样适用。原始新闻网页通常包含大量噪音。

import re from bs4 import BeautifulSoup import html2text def preprocess_news_html(html_content): """ 清洗HTML新闻内容,提取核心正文。 """ # 1. 使用BeautifulSoup解析,移除脚本、样式等标签 soup = BeautifulSoup(html_content, 'html.parser') for script in soup(["script", "style", "nav", "footer", "aside", "header"]): script.decompose() # 2. 尝试通过启发式方法或库(如readability-lxml)找到正文主体 # 这里简化处理,假设正文在<article>或包含大量文本的<div>中 article = soup.find('article') or soup.find('div', class_=re.compile(r'(content|article|post-body)')) if not article: article = soup.body # 兜底方案 # 3. 将HTML转换为纯文本,并规范化 h = html2text.HTML2Text() h.ignore_links = False # 保留链接有时有用 h.ignore_images = True text = h.handle(str(article)) # 4. 清理多余空白、换行 text = re.sub(r'\n\s*\n', '\n\n', text) # 将多个空行合并为一个 text = re.sub(r'[ \t]+', ' ', text) # 合并多个空格 text = text.strip() return text def preprocess_plain_text(raw_text): """ 对纯文本进行基础清洗。 """ # 移除URL(可选,有时URL包含信息) # text = re.sub(r'https?://\S+', '', raw_text) # 移除常见的报道来源后缀(如“澎湃新闻记者报道”、“路透社电”) lines = raw_text.split('\n') cleaned_lines = [line for line in lines if not re.search(r'(记者|报道|电|消息人士称).*$', line)] text = '\n'.join(cleaned_lines) # 统一日期格式(可选,可在后处理中做) # text = re.sub(r'(\d{4})年(\d{1,2})月(\d{1,2})日', r'\1-\2-\3', text) return text

4.2 后处理与数据入库:从JSON到数据库

Gemini返回的JSON需要经过验证和转换,才能变成可用的数据。

import sqlite3 from datetime import datetime def validate_and_store(data, news_source_id, conn): """ 验证数据并存入SQLite数据库。 """ cursor = conn.cursor() # 1. 基础验证 if not data or 'events' not in data: print("无效的抽取数据") return False # 2. 存储新闻元数据(假设有news_articles表) cursor.execute(''' INSERT OR REPLACE INTO news_articles (id, source_id, raw_url, title, summary, processed_at) VALUES (?, ?, ?, ?, ?, ?) ''', (news_source_id, news_source_id, data.get('original_url', ''), data.get('title', ''), data.get('summary', ''), datetime.utcnow())) article_id = cursor.lastrowid # 3. 存储事件 for event in data.get('events', []): cursor.execute(''' INSERT INTO events (article_id, description, date, type) VALUES (?, ?, ?, ?) ''', (article_id, event.get('description'), event.get('date'), event.get('type'))) # 4. 存储实体(需去重,同一篇文章中同一实体只存一次) entity_map = {} # 用于映射实体名到数据库ID for entity in data.get('entities', []): cursor.execute(''' INSERT OR IGNORE INTO entities (name, type) VALUES (?, ?) ''', (entity.get('name'), entity.get('type'))) cursor.execute('SELECT id FROM entities WHERE name = ?', (entity.get('name'),)) entity_id = cursor.fetchone()[0] entity_map[entity['name']] = entity_id # 存储实体与文章的关系 cursor.execute(''' INSERT INTO article_entities (article_id, entity_id, role_in_news) VALUES (?, ?, ?) ''', (article_id, entity_id, entity.get('role_in_news'))) # 5. 存储关系(需要from/to实体都已存在) for rel in data.get('relationships', []): from_id = entity_map.get(rel.get('from_entity')) to_id = entity_map.get(rel.get('to_entity')) # 如果to_entity指向的是一个事件描述,这里需要特殊处理,简化起见先存文本 if from_id and to_id: cursor.execute(''' INSERT INTO relationships (article_id, from_entity_id, to_entity_id, relation_type) VALUES (?, ?, ?, ?) ''', (article_id, from_id, to_id, rel.get('relation'))) # ... 类似地存储属性、情感分析等 conn.commit() return True

4.3 管道串联与调度

将以上模块串联起来,就形成了一个完整的处理管道。对于生产环境,你需要考虑:

  • 错误处理与重试:API调用可能失败,JSON可能解析错误。需要加入重试机制和死信队列,记录失败案例供后续排查。
  • 速率限制:遵守Gemini API的调用频率限制,在代码中加入time.sleep或使用更高级的队列。
  • 增量处理:记录已处理新闻的ID或哈希,避免重复处理。
  • 监控与日志:记录每篇文章的处理状态、耗时、消耗的token数,便于成本分析和性能优化。

一个简单的脚本骨架如下:

import time from your_news_fetcher import fetch_latest_news # 假设的新闻获取函数 def main_pipeline(): conn = sqlite3.connect('groundsource.db') news_items = fetch_latest_news() # 获取一批新闻 for item in news_items: print(f"处理: {item['title'][:50]}...") # 1. 预处理 clean_text = preprocess_news_html(item['content']) # 2. 调用Gemini抽取 structured_data = extract_structured_data(clean_text) if not structured_data: print(f" 抽取失败,跳过") continue # 3. 补充元数据 structured_data['original_url'] = item['url'] structured_data['title'] = item['title'] # 4. 存储 success = validate_and_store(structured_data, item['id'], conn) if success: print(f" 处理成功") # 5. 控制请求速率 time.sleep(1) # 避免触发API速率限制 conn.close()

5. 实战挑战与调优经验

在实际运行Groundsource的过程中,我遇到了不少预料之中和预料之外的问题。这里分享一些核心的挑战和解决思路。

5.1 模型输出的不稳定性与应对

即使设置了低temperature,Gemini的输出偶尔也会出现格式偏差或内容“幻觉”。

  • 问题1:JSON格式错误。模型有时会在JSON外添加markdown代码块标记,有时会漏掉逗号或括号。
    • 解决:在解析前加入强健的清洗和修复逻辑。如上文代码所示,先尝试剥离```标记。还可以使用json5库(比标准json更宽松)进行解析,或者编写简单的正则进行修复。
  • 问题2:实体归一化。同一家公司,可能被模型识别为“Apple”、“苹果公司”、“Apple Inc.”。这会导致数据库中产生多个重复实体。
    • 解决:在后处理阶段加入实体链接或模糊匹配。例如,维护一个已知实体的别名词典,或者使用字符串相似度算法(如Levenshtein距离、Jaccard相似度)进行聚类。对于重要实体(如上市公司),可以接入知识图谱API(如Wikidata)进行规范。
  • 问题3:日期解析模糊。新闻中常说“昨日”、“上周三”,模型需要结合新闻发布日期来推断具体日期。
    • 解决:在提示词中明确要求输出“YYYY-MM-DD”格式,并将新闻的发布日期作为上下文提供给模型。例如,在提示词开头加上“当前参考日期为:2023-10-27”。模型能很好地利用这个参考日期来解析相对时间。

5.2 提示词的迭代与优化

提示词不是一蹴而就的。我通过“评估-调整”循环来优化它。

  1. 创建黄金标准数据集:手动标注10-20篇不同类型的新闻,作为标准答案。
  2. 批量测试:用初始提示词处理这批新闻,将输出与标准答案对比。
  3. 分析错误模式
    • 遗漏提取:模型忽略了某些重要信息。解决:在提示词中更强调该信息,或改变描述方式。
    • 错误归类:例如将“产品发布”错误归类为“公司动态”。解决:在提示词中提供更清晰、更具体的类型定义和例子。
    • 过度解读:模型从暗示中推断出不存在的事实。解决:在提示词中强调“仅基于原文明确陈述的信息”,并加强source_references的要求。
  4. 迭代更新:根据分析结果,微调提示词的指令、示例和格式要求。这个过程可能重复多次。

5.3 成本控制与性能权衡

Gemini API是按token计费的,输入和输出都算。长新闻、复杂的提示词都会增加成本。

  • 策略1:文本截断与摘要:对于超长文章,可以先使用Gemini或其他更快的模型(如gemini-1.5-flash)生成一个简洁的摘要,再将摘要和关键段落(如开头、引语、结论)一起发送给主模型进行深度抽取。这能大幅减少输入token。
  • 策略2:缓存与去重:如果处理来自不同源的相同新闻(转载),可以通过计算内容哈希来识别并跳过重复处理。
  • 策略3:异步与批处理:设计异步处理管道,积累一定数量的新闻后再批量调用API(如果API支持批处理),可以减少网络开销,并更好地规划请求速率。
  • 策略4:模型选择:对于实时性要求不高或复杂度较低的任务,可以尝试使用gemini-1.5-flash,它速度更快、成本更低,虽然在复杂推理上稍弱于Pro版本。

5.4 结果验证与人工审核闭环

完全依赖AI抽取的数据不可能100%准确。对于关键业务场景,必须建立验证机制。

  • 抽样审核:定期随机抽取一定比例的处理结果,由人工进行审核,计算准确率、召回率等指标。
  • 置信度评分:可以尝试在提示词中要求模型对自己抽取的每条信息给出一个置信度评分(例如,基于原文明确程度)。低置信度的结果可以标记出来供人工重点审核。
  • 异常检测:设定一些业务规则。例如,如果某篇财经新闻中抽取出“股价上涨1000%”这样的极端属性,可以自动触发警报,交由人工复核。

6. 应用场景与扩展思考

Groundsource搭建的这套从非结构化文本到结构化数据的管道,其应用远不止于新闻分析。

  • 竞品监控:自动从科技媒体、博客、论坛中提取竞争对手的产品发布、功能更新、定价策略、用户反馈,形成动态的竞品情报面板。
  • 舆情分析:对社交媒体帖子、评论、论坛讨论进行情感分析和主题提取,量化公众对某个品牌、事件或政策的态度变化。
  • 学术文献挖掘:处理研究论文的摘要和引言部分,自动提取研究问题、方法、核心结论和领域关键词,构建学术知识图谱。
  • 内部报告分析:将公司内部的会议纪要、项目报告、客户沟通邮件等文档自动化处理,提取关键决策、任务分配和风险点。

扩展方向:

  1. 多语言支持:Gemini原生支持多语言。只需将提示词翻译成目标语言,即可处理不同语种的新闻,构建全球事件视图。
  2. 实时流处理:将批处理管道升级为流处理管道(如使用Apache Kafka),对接新闻推送流,实现近实时的情报生成。
  3. 与知识图谱深度融合:将抽取出的实体和关系,与现有的知识图谱(如Wikidata、企业自建图谱)进行链接和融合,让数据产生更大的网络效应。
  4. 可视化前端:为生成的结构化数据开发一个前端看板,用时间线、关系图、热力图等方式直观展示事件发展、实体关联和舆情趋势。

这个项目让我深刻体会到,大语言模型真正的威力不在于替代人类,而在于充当一个不知疲倦、高度一致的“初级分析师”。它将人类从信息搜集和初步整理的重复劳动中解放出来,让我们能更专注于更高层次的洞察、判断和决策。Groundsource只是一个起点,如何设计提示词来“驯服”模型,如何构建稳健的数据管道来处理模型的输出,如何将AI的产出与人类的专业知识相结合,这些才是更值得持续探索的课题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/2 6:38:39

Redis 详解:Redis 与 MySQL 的区别、数据类型与缓存三大问题

一、什么是 Redis&#xff1f;Redis 是一个开源的、基于内存的 Key-Value 数据库&#xff0c;全称是 Remote Dictionary Server。与传统的 MySQL 不同&#xff0c;Redis 的数据主要存储在内存中&#xff0c;因此具有非常高的读写性能&#xff0c;常被用于&#xff1a;缓存Sessi…

作者头像 李华
网站建设 2026/8/2 6:37:11

ESP32-S3-LCD-1.47开发板:从硬件解析到LVGL图形界面实战

1. 从一块屏幕说起&#xff1a;为什么是ESP32-S3-LCD-1.47&#xff1f;如果你最近在逛一些硬件开发社区或者开源硬件平台&#xff0c;大概率会刷到“ESP32-S3-LCD-1.47”这个看起来像是一串产品型号的词汇。它不是一个单纯的芯片&#xff0c;也不是一块普通的屏幕&#xff0c;而…

作者头像 李华
网站建设 2026/8/2 6:34:35

网络安全自学路线:从零基础到实战入门,保姆级指南

最近在后台收到不少私信&#xff0c;很多同学对网络安全感兴趣&#xff0c;想自学却不知从何下手。网上的资料要么过于零散不成体系&#xff0c;要么上来就是一堆晦涩难懂的术语&#xff0c;劝退了不少热情。作为一名在安全领域摸爬滚打多年的从业者&#xff0c;我深知一个清晰…

作者头像 李华
网站建设 2026/8/2 6:34:10

VMware安装Ubuntu虚拟机:从原理到实战的完整指南

1. 从零到一&#xff1a;为什么选择VMware与Ubuntu的组合&#xff1f;如果你刚接触Linux开发&#xff0c;或者需要在Windows/macOS上搭建一个隔离、纯净的测试环境&#xff0c;那么“在VMware里装个Ubuntu”几乎是所有人的第一站。这听起来像是个老生常谈的话题&#xff0c;网上…

作者头像 李华
网站建设 2026/8/2 6:34:08

小程序商城到店自提怎么用?手把手教你从零上手(附实操教程)

在微信生态做电商&#xff0c;到店自提是绕不开的核心能力。一、为什么需要这个功能&#xff1f;在竞争激烈的小程序电商赛道&#xff0c;光有产品不够&#xff0c;到店自提是关键的一环。二、适用场景以下场景特别适合使用到店自提&#xff1a;• 【适用】非商家入驻情况下&am…

作者头像 李华
网站建设 2026/8/2 6:31:32

跨平台解密工具:RPG Maker资源解密完全指南

跨平台解密工具&#xff1a;RPG Maker资源解密完全指南 【免费下载链接】RPGMakerDecrypter Tool for decrypting and extracting RPG Maker XP, VX and VX Ace encrypted archives and MV and MZ encrypted files. 项目地址: https://gitcode.com/gh_mirrors/rp/RPGMakerDec…

作者头像 李华