XUnity.AutoTranslator-Gemini——调用Google的Gemini API, 实现Unity游戏中日文文本的自动翻译
XunityAutoTranslator-Gemini-API
本项目是一个使用 Flask 框架和 Google Gemini GenAI 模型构建的 Web API 服务,用于将日文unity游戏文本翻译成简体中文。
日文游戏文本AI翻译API (基于Google Gemini)
本项目是一个使用 Flask 框架和 Google Gemini GenAI 模型构建的 Web API 服务,用于将日文游戏文本翻译成简体中文。
功能特点
- AI 驱动翻译: 使用 Google Gemini GenAI 模型
gemini-2.0-flash-001进行高质量的日文到简体中文翻译。 - 游戏文本优化: 针对游戏文本特点进行了优化,例如保留格式标签、处理特殊符号、保留原文风格等。
- 质量检测与重试: 自动检测译文质量,当检测到译文包含日文或重复内容时,会自动重试翻译。
- 高并发处理: 使用 Flask 框架和 gevent WSGI 服务器,支持高并发请求处理。
- 异步请求处理: 使用队列和线程池异步处理翻译请求,避免阻塞主线程,提高服务器响应速度。
- 简单易用: 提供简洁的 HTTP GET API 接口
/translate,方便集成到各种游戏或工具中。
快速开始
1. 前置条件
- Python 3.6+
- 已安装必要的 Python 库 (见(###2-依赖库))
- Google Gemini API 密钥
2. 依赖库
请确保已安装以下 Python 库:
import os
import re
import json
import time
from flask import Flask, request
from gevent.pywsgi import WSGIServer
from urllib.parse import unquote
from threading import Thread
from queue import Queue
import concurrent.futures
from google import genai # 导入 Google GenAI 库
配置说明
API 配置
Model_Type = "gemini-2.0-flash-001" # 使用的模型类型, 请根据Google的文档自行修改
client = genai.Client(api_key="YOUR_API_KEY") # 替换为你的 API 密钥
3. 配置 API 密钥
请修改代码,打开 脚本文件名.py 文件,找到以下代码行:
client = genai.Client(api_key=“YOUR_API_KEY”) # 使用 genai.Client 初始化客户端,并配置 API 密钥 请替换为您的 API 密钥
将 “YOUR_API_KEY” 替换为您自己的 Google Gemini API 密钥。 注意:请务必替换为您自己的 API 密钥,否则API将无法正常工作。
4. 运行 API 服务 在代码所在目录下,打开终端并执行以下命令:
python 脚本文件名.py
配置XUnity.AutoTranslator看我上一篇文章:
XUnity.AutoTranslator-deepseek——调用腾讯的DeepSeek V3 API,实现Unity游戏中日文文本的自动翻译
代码配置
以下参数在代码中直接定义,您可以根据需要修改代码进行调整:
- Model_Type: 使用的 Google Gemini GenAI 模型类型,默认为 “gemini-2.0-flash-001”。您可以根据 Google GenAI API 的支持情况选择其他模型。
- repeat_count: 重复内容检测阈值,默认为 5。用于检测译文中是否存在重复内容,数值越大,对重复内容检测的容忍度越高。
- prompt: 基础提示词 (Prompt),用于指导 AI 模型进行翻译。您可以根据需要修改提示词,以优化翻译效果。
- prompt_list: 提示词列表,默认为包含单个基础提示词的列表。您可以配置多个提示词,程序会在翻译失败时自动尝试使用列表中的下一个提示词进行重试翻译。
- MAX_WORKERS: 线程池最大工作线程数,默认为 2。您可以根据服务器性能和并发需求调整线程池大小。
代码如下:
import os
import re
import json
import time
from flask import Flask, request
from gevent.pywsgi import WSGIServer
from urllib.parse import unquote
from threading import Thread
from queue import Queue
import concurrent.futures
from google import genai # 导入 Google GenAI 库# 启用虚拟终端序列,支持 ANSI 转义代码,允许在终端显示彩色文本
os.system('')# dict_path='用户替换字典.json' # 替换字典路径。如果不需要使用替换字典,请将此变量留空(设为 None 或空字符串 "")
dict_path=None # 替换字典路径。如果不需要使用替换字典,请将此变量留空(设为 None 或空字符串 "")
# API 配置参数
Model_Type = "gemini-2.0-flash-001" # 使用的模型类型,选择 GenAI 支持的模型,例如 "gemini-2.0-flash"# 创建 Google GenAI 客户端实例
# 使用 genai.Client 进行客户端初始化,并配置 API 密钥
# 注意:请将 "YOUR_API_KEY" 替换为您自己的 Google GenAI API 密钥
client = genai.Client(api_key="YOUR_API_KEY") # 使用 genai.Client 初始化客户端,并配置 API 密钥 **请替换为您的 API 密钥**# 译文重复内容检测参数
repeat_count=5 # 重复内容阈值。如果译文中有任意单字或单词连续重复出现次数大于等于 repeat_count,则认为译文质量不佳,会触发重试翻译逻辑# 提示词 (Prompt) 配置
prompt= '''
你是资深本地化专家,负责将游戏日文文本译为简体中文。
**你的任务是精确翻译日文文本,仅输出译文,请勿添加任何与原文无关的解释、说明、补充信息或其他任何文字。** 接收文本后,请严格按照以下要求翻译:
翻译范围:翻译普通日文文本,保留原文叙述风格。
保留格式:保留转义字符、格式标签等非日文文本内容。
翻译原则:忠实准确,确保语义无误;对露骨性描写,可直白粗俗表述,不删减篡改;对双关语等特殊表达,找目标语言等效表达,保原作意图风格。
文本类型:游戏文本含角色对话、旁白、武器及物品名称、技能描述、格式标签、特殊符号等。
以下是待翻译的游戏文本:''' # 基础提示词,用于指导模型进行翻译,定义了翻译的角色、范围、格式、原则和文本类型
prompt_list=[prompt] # 提示词列表。可以配置多个提示词,程序会依次尝试使用列表中的提示词进行翻译,直到获得满意的结果
# l=len(prompt_list) # 获取提示词列表的长度 (此变量目前未被直接使用,移除)# 提示字典相关的提示词配置
dprompt0='\n在翻译中使用以下字典,字典的格式为{\'原文\':\'译文\'}\n' # 提示模型在翻译时使用提供的字典。字典格式为 JSON 格式的字符串,键为原文,值为译文
dprompt1='\nDuring the translation, use a dictionary in {\'Japanese text \':\'translated text \'} format\n' # 英文版的字典提示词,可能用于多语言支持或模型偏好
# dprompt_list 字典提示词列表,与 prompt_list 提示词列表一一对应。当使用 prompt_list 中的第 i 个提示词时,会同时使用 dprompt_list 中的第 i 个字典提示词
dprompt_list=[dprompt0,dprompt1,dprompt1]
MAX_WORKERS = 2 # 线程池最大工作线程数 (直接在代码中定义)app = Flask(__name__) # 创建 Flask 应用实例# 读取提示字典
prompt_dict= {} # 初始化提示字典为空字典
if dict_path: # 检查是否配置了字典路径try:with open(dict_path, 'r', encoding='utf8') as f: # 尝试打开字典文件tempdict = json.load(f) # 加载 JSON 字典数据# 按照字典 key 的长度从长到短排序,确保优先匹配长 key,避免短 key 干扰长 key 的匹配sortedkey = sorted(tempdict.keys(), key=lambda x: len(x), reverse=True)for i in sortedkey:prompt_dict[i] = tempdict[i] # 将排序后的字典数据存入 prompt_dictprint(f"\033[32m字典文件 {dict_path} 加载成功,共加载 {len(prompt_dict)} 个词条。\033[0m") # 打印字典加载成功的消息except FileNotFoundError:print(f"\033[33m警告:字典文件 {dict_path} 未找到。\033[0m") # 警告用户字典文件未找到except json.JSONDecodeError:print(f"\033[31m错误:字典文件 {dict_path} JSON 格式错误,请检查字典文件。\033[0m") # 错误提示 JSON 格式错误except Exception as e:print(f"\033[31m读取字典文件时发生未知错误: {e}\033[0m") # 捕获其他可能的文件读取或 JSON 解析错误def contains_japanese(text):"""检测文本中是否包含日文字符。"""pattern = re.compile(r'[\u3040-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FE]') # 日文字符的 Unicode 范围正则表达式return pattern.search(text) is not None # 使用正则表达式搜索文本中是否包含日文字符def has_repeated_sequence(string, count):"""检测字符串中是否存在连续重复的字符或子串。"""# 检查单个字符的重复for char in set(string):if string.count(char) >= count:return True# 检查字符串片段(子串)的重复for size in range(2, len(string) // count + 1):for start in range(0, len(string) - size + 1):substring = string[start:start + size]matches = re.findall(re.escape(substring), string)if len(matches) >= count:return Truereturn False# 获得文本中包含的字典词汇 (优化后)
def get_dict(text, dictionary):"""从文本中提取出在提示字典 (dictionary) 中存在的词汇及其翻译 (优化版本,不修改原文).Args:text (str): 待处理的文本.dictionary (dict): 提示字典.Returns:dict: 一个字典,key 为在文本中找到的字典原文,value 为对应的译文.如果文本中没有找到任何字典词汇,则返回空字典."""res = {}for key in dictionary:if key in text:res[key] = dictionary[key]return resrequest_queue = Queue() # 创建请求队列
def handle_translation(text, translation_queue):"""处理翻译请求的核心函数."""text = unquote(text) # URL 解码max_retries = 3 # 最大 API 请求重试次数retries = 0 # 重试计数器special_chars = [',', '。', '?','...'] # 句末特殊字符text_end_special_char = Noneif text and text[-1] in special_chars: # 避免空字符串索引错误text_end_special_char = text[-1]special_char_start = "「"special_char_end = "」"has_special_start = text.startswith(special_char_start)has_special_end = text.endswith(special_char_end)if has_special_start and has_special_end:text = text[len(special_char_start):-len(special_char_end)]try: # 捕获 API 异常dict_inuse = get_dict(text, prompt_dict) # 获取字典词汇 (优化: 仅调用一次)for i in range(len(prompt_list)): # 遍历提示词列表prompt = prompt_list[i]if dict_inuse: # 如果有字典词汇,则添加字典提示prompt += dprompt_list[i] + str(dict_inuse)content_to_translate = prompt + text # 构建完整的翻译内容response_test = client.models.generate_content( # API 调用model=Model_Type, contents=content_to_translate)translations = response_test.textprint(f"【API 原始输出 (未经处理):】\n{repr(translations)}") # 打印原始值if translations.endswith("\n"): # 移除尾部换行符translations = translations[:-1]print(f"【API 翻译结果 (经处理):】\n{repr(translations)}") # 打印处理后的值,用于调试或日志记录# print(f'{prompt}\n{translations}') # 打印提示词和翻译结果, 调试用if has_special_start and has_special_end: # 特殊字符处理if not translations.startswith(special_char_start):translations = special_char_start + translationsif not translations.endswith(special_char_end):translations = translations + special_char_endtranslation_end_special_char = Noneif translations and translations[-1] in special_chars: # 避免空字符串索引错误translation_end_special_char = translations[-1]if text_end_special_char and translation_end_special_char:if text_end_special_char != translation_end_special_char:translations = translations[:-1] + text_end_special_charelif text_end_special_char and not translation_end_special_char:translations += text_end_special_charelif not text_end_special_char and translation_end_special_char:translations = translations[:-1]contains_japanese_characters = contains_japanese(translations) # 检测日文repeat_check = has_repeated_sequence(translations, repeat_count) # 重复检测if not contains_japanese_characters and not repeat_check: # 质量检测通过则跳出循环breakelif contains_japanese_characters:print("\033[31m检测到译文中包含日文字符,尝试使用下一个提示词进行翻译。\033[0m")continueelif repeat_check:print("\033[31m检测到译文中存在重复短语。\033[0m")# 可以在此处添加更复杂的重试策略,例如更换提示词组合,调整模型参数等 (当前版本暂未实现)breakif not contains_japanese_characters and not repeat_check: # 最终质量检测pass # 翻译成功print(f"\033[36m[译文]\033[0m:\033[31m {translations}\033[0m")print("-------------------------------------------------------------------------------------------------------")translation_queue.put(translations) # 放入结果队列except Exception as e: # API 异常处理retries += 1print(f"\033[31mAPI请求超时或发生错误 (第 {retries} 次重试): {e}\033[0m") # 打印错误信息if retries == max_retries:print(f"\033[31m达到最大重试次数,翻译失败。\033[0m")translation_queue.put(False) # 放入失败标志return # 达到最大重试次数,返回time.sleep(1) # 等待重试handle_translation(text, translation_queue) # 递归重试return # 重试后返回@app.route('/translate', methods=['GET'])
def translate():"""Flask 路由函数,处理 "/translate" GET 请求."""text = request.args.get('text') # 获取待翻译文本print(f"\033[36m[原文]\033[0m \033[35m{text}\033[0m") # 打印原文translation_queue = Queue() # 创建结果队列request_queue.put_nowait(text) # 放入请求队列with concurrent.futures.ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor: # 使用配置的线程池大小 (直接使用硬编码值)future = executor.submit(handle_translation, text, translation_queue) # 提交翻译任务try: # 超时处理translation_result = future.result(timeout=30) # 获取结果,设置超时时间except concurrent.futures.TimeoutError:print("\033[31m翻译请求超时。\033[0m") # 打印超时信息return "[请求超时] " + text, 500 # 返回超时错误translation = translation_queue.get() # 获取翻译结果request_queue.get_nowait() # 从请求队列移除已处理请求if isinstance(translation, str): # 翻译成功return translation # 返回翻译结果else: # 翻译失败return "[翻译失败] " , 500 # 返回失败状态码def main():"""主函数,启动 Flask 应用和 gevent 服务器."""print("\033[31m服务器在 http://127.0.0.1:4000 上启动\033[0m") # 启动信息http_server = WSGIServer(('127.0.0.1', 4000), app, log=None, error_log=None) # 创建 gevent WSGIServer 实例http_server.serve_forever() # 启动服务器if __name__ == '__main__':main() # 运行主函数
我的上一篇帖子:XUnity.AutoTranslator-deepseek——调用腾讯的DeepSeek V3 API,实现Unity游戏中日文文本的自动翻译
本项目地址:项目地址
相关文章:
XUnity.AutoTranslator-Gemini——调用Google的Gemini API, 实现Unity游戏中日文文本的自动翻译
XunityAutoTranslator-Gemini-API 本项目是一个使用 Flask 框架和 Google Gemini GenAI 模型构建的 Web API 服务,用于将日文unity游戏文本翻译成简体中文。 日文游戏文本AI翻译API (基于Google Gemini) 本项目是一个使用 Flask 框架和 Google Gemini GenAI 模型…...
中文Build a Large Language Model (From Scratch) 免费获取全文
中文pdf下载地址:https://pan.baidu.com/s/1aq2aBcWt9vYagT2-HuxdWA?pwdlshj 提取码:lshj 原文、代码、视频项目地址:https://github.com/rasbt/LLMs-from-scratch 翻译工具:沉浸式翻译(https://app.immersivetrans…...
DeepSeek 助力 Vue 开发:打造丝滑的瀑布流布局(Masonry Layout)
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 Deep…...
C++:从拷贝构造函数到深浅拷贝
拷贝构造函数 当实例化一个新对象并使用同类型对其进行初始化时,会显式调用类的拷贝构造函数,拷贝构造函数写法:形参为const修饰的同类型类引用。拷贝构造函数有个需要注意的点,形参为何是只允许传递引用呢?原因在于若…...
Openssl之SM2加解密命令
### 1. 生成 SM2 私钥openssl genpkey -algorithm EC \-pkeyopt ec_paramgen_curve:sm2 \-out sm2_private_key.pem### 2. 从私钥导出 SM2 公钥openssl pkey -in sm2_private_key.pem \-pubout \-out sm2_public_key.pem### 3. 使用 SM2 公钥加密openssl pkeyutl -encrypt \-pu…...
Java集合框架之List接口详解
目录 一、List接口概述 二、List接口常见实现类 三、List接口特有方法: 1.元素操作 2. 查找元素位置 3. 子列表与不可变列表 四、List特有迭代器:ListIterator 1.特有的迭代方式 2.ListIterator接口中的常用方法: ⑴.void add(E e):在光标位置插入元素。(会移动…...
oracle apex post接口
日常记录 使用到了apex_json方式接收 、、、1 首先,接口通过body传递过来,成功接收到, 数据格式为 JSON_OBJECT_T l_json : JSON_OBJECT_T.parse(:body); 这里我用参数接收到 然后 里面是包含了 "data" 我用 继续接收到这个 l…...
【数据挖掘】--算法
【数据挖掘】--算法 目录:1. 缺失值和数值属性处理1缺失值处理: 2. 用于文档分类的朴素贝叶斯3. 分治法:建立决策树4. 覆盖算法建立规则5. 挖掘关联规则6. 线性模型有效寻找最近邻暴力搜索(Brute-Force Search)kd树&am…...
halcon机器视觉深度学习对象检测,物体检测
目录 效果图操作步骤软件版本halcon参考代码本地函数 get_distinct_colors()本地函数 make_neighboring_colors_distinguishable() 效果图 操作步骤 首先要在Deep Learning Tool工具里面把图片打上标注文本, 然后训练模型,导出模型文件 这个是模型 mod…...
英文字体:极简现代浓缩未来派科技海报标题排版无衬线字体 PODIUM Sharp Font
PODIUM Sharp 是 2012 年设计的 DUDU 字体的扩展版本。多年后,我决定通过添加新的母版和粗细来重建和开发这种字体。最后,PODIUM Sharp 由 234 种款式组成:从超压缩发际线到超扩展重度。 这个项目的主要目的是在我在旧波兰标本中发现的不同模…...
Java中JDK、JRE,JVM之间的关系
Java中的JDK、JRE和JVM是三个核心概念,其关系可概括为JDK > JRE > JVM,具体如下: 一、定义与作用 JDK(Java Development Kit) 定义:Java开发工具包,用于开发和编译Java程序。包含内容&…...
elasticsearch在windows上的配置
写在最前面: 上资源 第一步 解压: 第二步 配置两个环境变量 第三步 如果是其他资源需要将标蓝的文件中的内容加一句 xpack.security.enabled: false 不同版本的yaml文件可能配置不同,末尾加这个 xpack.security.enabled: true打开bin目…...
vscode 配置 Copilot 提示GHE.com连接失败
步骤一:打开设置并进入 settings.json 点击菜单栏中的 “文件” -> “首选项” -> “设置”。 在搜索设置栏中输入 “Copilot: Advanced”。 点击搜索结果下方的 “在 settings.json 中编辑” 链接,这会打开 settings.json 文件。 步骤二&#…...
Pycharm+CodeGPT+Ollama+Deepseek
首先,体验截图: 接着: 1、下载Ollama: Download Ollama on macOS 2、下载模型 以1.5b为例,打开命令行,输入: ollama run deepseek-r1:1.5b 3、Pycharm安装Code GPT插件 打开PyCharm,找到文…...
Unreal5从入门到精通之在编辑器中更新 UserWidgets
前言 在虚幻中创建越来越复杂和灵活的 UserWidget 蓝图时,一个问题是它们在编辑器中的外观与它们在游戏中的最终外观可能有很大不同。 库存面板示例 假设你想创建一个通用的库存显示小部件。我们可以在整个 UI 中使用它,无论我们需要在哪里显示某些内容。 标题,描述所显示…...
C语言修炼手册
目录 第一章 分支与循环语句 1. 悬空else问题 2. 循环输入问题 3. getchar缓冲区溢出问题 4. goto语句坑点 第二章 函数 1.为什么要有库函数 2.函数嵌套 3.链式访问 4.回调函数 5.函数递归 6.字符转换函数 7.模拟实现字符串拷贝strcpy 8.模拟实现字符串的长度s…...
Linux部署ollama
1、下载ollama wget https://github.com/ollama/ollama/releases/download/v0.1.47/ollama-linux-amd64或者curl -fsSL https://ollama.com/install.sh | sh2、安装ollama install ollama-linux-amd64 /usr/local/bin/ollama3、启动ollama vi /etc/systemd/system/ollama.se…...
跨语言语义理解与生成:多语言预训练方法及一致性优化策略
网罗开发 (小红书、快手、视频号同名) 大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等…...
最新华为 HCIP-Datacom(H12-821)2025.2.20
最新 HCIP-Datacom(H12-821),完整题库请扫描上方二维码访问。 如图所示为某OSPF网络,已知R1和R2已,成功建立邻接关系,现一工程师在R2上配置了图中命令。那么在R2上查看LSDB时,可能存在以下哪些LSA? A&…...
TS语言自定义脚手架
初始化 新建文件夹初始化命令 npm init -ytsc --initnpm i types/nodenpm i typescript# 处理别名npm i -D tsc-alias -y 表示选项都为yes 安装ts相关依赖 新建相关文件 bin 文件夹 src文件夹 commands 文件夹 (命令 utils 文件夹 (封装方法) index.t…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
windows系统MySQL安装文档
概览:本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容,为学习者提供全面的操作指导。关键要点包括: 解压 :下载完成后解压压缩包,得到MySQL 8.…...
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南 背景介绍完整操作步骤1. 创建Docker容器环境2. 验证GUI显示功能3. 安装ROS Noetic4. 配置环境变量5. 创建ROS节点(小球运动模拟)6. 配置RVIZ默认视图7. 创建启动脚本8. 运行可视化系统效果展示与交互技术解析ROS节点通…...
云原生安全实战:API网关Envoy的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关 作为微服务架构的统一入口,负责路由转发、安全控制、流量管理等核心功能。 2. Envoy 由Lyft开源的高性能云原生…...
Axure零基础跟我学:展开与收回
亲爱的小伙伴,如有帮助请订阅专栏!跟着老师每课一练,系统学习Axure交互设计课程! Axure产品经理精品视频课https://edu.csdn.net/course/detail/40420 课程主题:Axure菜单展开与收回 课程视频:...
Linux入门(十五)安装java安装tomcat安装dotnet安装mysql
安装java yum install java-17-openjdk-devel查找安装地址 update-alternatives --config java设置环境变量 vi /etc/profile #在文档后面追加 JAVA_HOME"通过查找安装地址命令显示的路径" #注意一定要加$PATH不然路径就只剩下新加的路径了,系统很多命…...
Python异步编程:深入理解协程的原理与实践指南
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 持续学习,不断…...
理想汽车5月交付40856辆,同比增长16.7%
6月1日,理想汽车官方宣布,5月交付新车40856辆,同比增长16.7%。截至2025年5月31日,理想汽车历史累计交付量为1301531辆。 官方表示,理想L系列智能焕新版在5月正式发布,全系产品力有显著的提升,每…...
Pandas 可视化集成:数据科学家的高效绘图指南
为什么选择 Pandas 进行数据可视化? 在数据科学和分析领域,可视化是理解数据、发现模式和传达见解的关键步骤。Python 生态系统提供了多种可视化工具,如 Matplotlib、Seaborn、Plotly 等,但 Pandas 内置的可视化功能因其与数据结…...
