Browse Source

Merge branch 'new_dev' of https://github.com/deepcloud2048/deep_voice into liwei_wakeup

newdev_shunjiawei
liwei1dao 10 months ago
parent
commit
80ee218312
  1. 18
      README.md
  2. 16
      android/app/src/main/AndroidManifest.xml
  3. 51
      android/app/src/main/kotlin/com/saitong/voitrans/FloatingWindowService.kt
  4. BIN
      assets/images/DefaultPicture.jpg
  5. BIN
      assets/images/defaultPicture.png
  6. BIN
      assets/images/headphone_new3.png
  7. BIN
      assets/images/headphone_new4.png
  8. 170
      doc/yhxy.html
  9. 151
      doc/yhxy_en.html
  10. 397
      doc/ysxy.html
  11. 381
      doc/ysxy_en.html
  12. 9
      ios/Runner/Info.plist
  13. 5
      ios/Runner/RunnerProfile.entitlements
  14. 11
      lib/core/bindings/initial_binding.dart
  15. 136
      lib/core/translations/language/ar_sa.dart
  16. 34
      lib/core/translations/language/bg_bg.dart
  17. 35
      lib/core/translations/language/cs_cz.dart
  18. 36
      lib/core/translations/language/da_dk.dart
  19. 134
      lib/core/translations/language/de_de.dart
  20. 49
      lib/core/translations/language/el_gr.dart
  21. 354
      lib/core/translations/language/en_us.dart
  22. 70
      lib/core/translations/language/es_es.dart
  23. 34
      lib/core/translations/language/et_ee.dart
  24. 37
      lib/core/translations/language/fa_ir.dart
  25. 38
      lib/core/translations/language/fi_fi.dart
  26. 88
      lib/core/translations/language/fr_fr.dart
  27. 140
      lib/core/translations/language/hi_in.dart
  28. 35
      lib/core/translations/language/hr_hr.dart
  29. 36
      lib/core/translations/language/hu_hu.dart
  30. 35
      lib/core/translations/language/id_id.dart
  31. 33
      lib/core/translations/language/is_is.dart
  32. 131
      lib/core/translations/language/it_it.dart
  33. 65
      lib/core/translations/language/ja_jp.dart
  34. 120
      lib/core/translations/language/ko_kr.dart
  35. 36
      lib/core/translations/language/lt_lt.dart
  36. 34
      lib/core/translations/language/lv_lv.dart
  37. 36
      lib/core/translations/language/ms_my.dart
  38. 36
      lib/core/translations/language/nb_no.dart
  39. 36
      lib/core/translations/language/nl_nl.dart
  40. 36
      lib/core/translations/language/pl_pl.dart
  41. 131
      lib/core/translations/language/pt_pt.dart
  42. 37
      lib/core/translations/language/ro_ro.dart
  43. 128
      lib/core/translations/language/ru_ru.dart
  44. 36
      lib/core/translations/language/sk_sk.dart
  45. 36
      lib/core/translations/language/sl_si.dart
  46. 36
      lib/core/translations/language/sr_rs.dart
  47. 37
      lib/core/translations/language/sv_se.dart
  48. 30
      lib/core/translations/language/th_th.dart
  49. 35
      lib/core/translations/language/tl_ph.dart
  50. 33
      lib/core/translations/language/tr_tr.dart
  51. 31
      lib/core/translations/language/uk_ua.dart
  52. 34
      lib/core/translations/language/vi_vn.dart
  53. 307
      lib/core/translations/language/zh_cn.dart
  54. 153
      lib/core/translations/language/zh_hk.dart
  55. 17
      lib/core/widgets/intro_overlay_builder.dart
  56. 2
      lib/data/models/appconfig_model.dart
  57. 2
      lib/data/models/appconfig_model.g.dart
  58. 10
      lib/data/models/channel_app_model.dart
  59. 4
      lib/data/models/channel_app_model.g.dart
  60. 239
      lib/data/models/goods.dart
  61. 292
      lib/data/models/meeting_usage_stats.dart
  62. 41
      lib/data/models/translation_usage_stats.dart
  63. 95
      lib/data/models/user_Info.dart
  64. 8
      lib/data/services/account_service.dart
  65. 5
      lib/data/services/asr_service.dart
  66. 133
      lib/data/services/ble_manager.dart
  67. 15
      lib/data/services/bluetooth_manager.dart
  68. 4
      lib/data/services/deapsound_ai_service.dart
  69. 105
      lib/data/services/meeting/meeting_task_aggregator.dart
  70. 141
      lib/data/services/meeting/meeting_task_service.dart
  71. 971
      lib/data/services/meeting/meeting_task_service2.dart
  72. 82
      lib/data/services/meeting/meeting_upload_service.dart
  73. 187
      lib/data/services/meeting/summary_task_service.dart
  74. 64
      lib/data/services/network/api.dart
  75. 13
      lib/data/services/network/auth_interceptor.dart
  76. 16
      lib/data/services/network/dio_manager.dart
  77. 55
      lib/data/services/novice_guide_service.dart
  78. 18
      lib/data/services/ota_check_service.dart
  79. 821
      lib/data/services/pay_service.dart
  80. 6
      lib/data/services/speech_impl/azure_asr_service.dart
  81. 8
      lib/data/services/speech_impl/azure_tts_service.dart
  82. 5
      lib/data/services/speech_impl/voice_clone_tts_service.dart
  83. 5
      lib/data/services/speech_impl/volcano_asr_api_service.dart
  84. 5
      lib/data/services/speech_impl/volcano_asr_service.dart
  85. 5
      lib/data/services/speech_impl/volcano_tts_service.dart
  86. 5
      lib/data/services/speech_impl/xunfei_asr_service.dart
  87. 3
      lib/data/services/tts_service.dart
  88. 783
      lib/data/services/usage_stats_service.dart
  89. 140
      lib/data/services/version_update_service.dart
  90. 11
      lib/data/services/volcano_translation_service.dart
  91. 41
      lib/modules/agent/controllers/agent_controller.dart
  92. 66
      lib/modules/agent/views/agent_view.dart
  93. 5
      lib/modules/agent/views/message_bubble.dart
  94. 2
      lib/modules/common/widgets/language_selector_bar.dart
  95. 73
      lib/modules/common/widgets/recharge_dialog.dart
  96. 2
      lib/modules/devices/controllers/devices_controller.dart
  97. 171
      lib/modules/devices/views/devices_view.dart
  98. 10
      lib/modules/eq_settings/bindings/eq_settings_binding.dart
  99. 217
      lib/modules/eq_settings/controllers/eq_settings_controller.dart
  100. 95
      lib/modules/eq_settings/views/eq_settings_view.dart

18
README.md

@ -40,3 +40,21 @@ lib/
│
└─ main.dart # 程序入口
```
### 本地调试内购(IAP)流程
不需要真实购买即可在本地跑通前端内购流程:
- 在项目根目录的环境变量文件(如 `.env`)里添加:
```
APP_IAP_MOCK=1
```
- 作用:在 `PayService` 中启用“本地内购模拟”,调用 `processGooglePayment` 或 `processApplePayment` 会:
- 立即触发“已发起内购(本地模拟)”;
- 短暂延时后触发“支付处理中…(本地模拟)”;
- 再触发“支付成功(本地模拟)”。
- 注意:该模式不依赖 Google Play / App Store 安装来源,也不会进行服务器收据校验,仅用于前端 UI 与状态机验证。
- 关闭模拟:将 `APP_IAP_MOCK` 移除或设为 `0/false`,恢复真实内购流程。

16
android/app/src/main/AndroidManifest.xml

@ -41,7 +41,7 @@
<!-- 添加悬浮窗权限,可能有助于解决前台服务启动问题 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!-- 添加发送短信权限 -->
<uses-permission android:name="android.permission.SEND_SMS" />
<!-- <uses-permission android:name="android.permission.SEND_SMS" /> -->
<!-- 添加读取联系人权限 -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
<!-- 添加拨打电话权限 -->
@ -109,6 +109,20 @@
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="voitrans"/>
</intent-filter>
<!-- PayPal 网页回跳的深链:deepvoiceclient://paypal/return 与 /cancel -->
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="deepvoiceclient" android:host="paypal" android:pathPrefix="/return" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="deepvoiceclient" android:host="paypal" android:pathPrefix="/cancel" />
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->

51
android/app/src/main/kotlin/com/saitong/voitrans/FloatingWindowService.kt

@ -19,6 +19,7 @@ class FloatingWindowService : Service() {
private var windowManager: WindowManager? = null
private var floatingView: View? = null
private var isMinimized = true
private lateinit var layoutParams: WindowManager.LayoutParams
private lateinit var sourceTextView: TextView
private lateinit var translatedTextView: TextView
@ -73,7 +74,7 @@ class FloatingWindowService : Service() {
setupClickListeners()
// 设置窗口参数
val layoutParams = WindowManager.LayoutParams().apply {
layoutParams = WindowManager.LayoutParams().apply {
width = WindowManager.LayoutParams.WRAP_CONTENT
height = WindowManager.LayoutParams.WRAP_CONTENT
type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@ -255,26 +256,12 @@ class FloatingWindowService : Service() {
}
private fun setupClickListeners() {
// 最小化状态点击展开
minimizedView.setOnClickListener {
isMinimized = false
updateViewState(false)
notifyStateChange("expanded")
}
// 展开状态点击最小化
expandedView.setOnClickListener {
isMinimized = true
updateViewState(true)
notifyStateChange("minimized")
}
// 长按关闭
floatingView!!.setOnLongClickListener {
closeFloatingWindow()
true
}
// 拖拽功能
setupDragListener()
}
@ -284,25 +271,40 @@ class FloatingWindowService : Service() {
var initialY = 0
var initialTouchX = 0f
var initialTouchY = 0f
var dragging = false
val threshold = (4 * resources.displayMetrics.density).toInt()
floatingView!!.setOnTouchListener { _, event ->
when (event.action) {
MotionEvent.ACTION_DOWN -> {
val layoutParams = floatingView!!.layoutParams as WindowManager.LayoutParams
initialX = layoutParams.x
initialY = layoutParams.y
initialTouchX = event.rawX
initialTouchY = event.rawY
dragging = false
true
}
MotionEvent.ACTION_MOVE -> {
val layoutParams = floatingView!!.layoutParams as WindowManager.LayoutParams
layoutParams.x = initialX + (event.rawX - initialTouchX).toInt()
layoutParams.y = initialY + (event.rawY - initialTouchY).toInt()
val dx = (event.rawX - initialTouchX).toInt()
val dy = (event.rawY - initialTouchY).toInt()
if (Math.abs(dx) > threshold || Math.abs(dy) > threshold) dragging = true
val dm = resources.displayMetrics
val maxX = dm.widthPixels - (floatingView?.width ?: 0)
val maxY = dm.heightPixels - (floatingView?.height ?: 0)
layoutParams.x = (initialX + dx).coerceIn(0, maxX)
layoutParams.y = (initialY + dy).coerceIn(0, maxY)
windowManager?.updateViewLayout(floatingView, layoutParams)
true
}
else -> false
MotionEvent.ACTION_UP -> {
if (!dragging) {
isMinimized = !isMinimized
updateViewState(isMinimized)
notifyStateChange(if (isMinimized) "minimized" else "expanded")
}
dragging = false
true
}
else -> true
}
}
}
@ -347,11 +349,10 @@ class FloatingWindowService : Service() {
val x = intent.getIntExtra(EXTRA_X, 0)
val y = intent.getIntExtra(EXTRA_Y, 0)
floatingView?.let { view ->
val layoutParams = view.layoutParams as WindowManager.LayoutParams
floatingView?.let {
layoutParams.x = x
layoutParams.y = y
windowManager?.updateViewLayout(view, layoutParams)
windowManager?.updateViewLayout(it, layoutParams)
}
}

BIN
assets/images/DefaultPicture.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

BIN
assets/images/defaultPicture.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 KiB

BIN
assets/images/headphone_new3.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 774 KiB

BIN
assets/images/headphone_new4.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 904 KiB

170
doc/yhxy.html

@ -0,0 +1,170 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Voitrans应用用户协议</title>
<style>
body {
font-family: 'Arial', sans-serif;
line-height: 1.6;
margin: 0 auto;
max-width: 800px;
padding: 20px;
color: #333;
}
h1 {
text-align: center;
margin-bottom: 30px;
}
h2 {
margin-top: 30px;
border-bottom: 1px solid #eee;
padding-bottom: 10px;
}
p {
margin-bottom: 15px;
}
.indent {
padding-left: 20px;
}
</style>
</head>
<body>
<h1>Voitrans应用用户协议</h1>
<p>这些使用条款和条件告诉您如何使用Voitrans应用程序和在线服务("服务")进行访问。深圳市良闯时代科技有限公司(以下简称"良闯")在此特别提醒用户认真阅读、充分理解本《用户协议》(以下简称"本协议")。</p>
<p>用户应认真阅读、充分理解本协议中各条款。请您审慎阅读并选择接受或不接受本协议。您使用Voitrans APP(以下简称"本APP"或"本软件")等行为将视为对本协议的接受,并同意接受本协议各项条款的约束。如您不同意本协议,请勿使用本APP。良闯有权修订本协议,更新后的协议条款将公布于本APP,自公布之日起生效。</p>
<h2>一、总则</h2>
<p>1.1 本APP是良闯提供的用于连接良闯及其合作公司发布的耳机产品的软件,本软件及相关服务的所有权和运营权均归良闯所有。</p>
<p>1.2 本协议是您(以下简称"用户")与良闯及其合作公司以及运营合作单位(以下简称"合作单位")之间关于用户使用本APP及相关服务所订立的协议。</p>
<p>1.3 本软件及服务包括:</p>
<p class="indent">1.3.1 提供的软件为使用Voitrans的用户提供Voitrans的连接与绑定、功能设置管理等软件服务,具体以本APP 实际提供的软件服务为准。</p>
<p class="indent">1.3.2 本软件的更新、升级以及其他服务。</p>
<h2>二、软件授权范围</h2>
<p>2.1 良闯就本软件给予用户一项个人的、不可转让、不可转授权以及非独占性的许可。</p>
<p>2.2 用户可以为非商业目的在单一台移动终端设备上安装、使用、显示、运行本软件。但用户不得为商业运营目的安装、使用、运行本软件,不可以对本软件或者本软件运行过程中释放到任何终端设备内存中的数据及本软件运行过程中客户端与服务器端的交互数据进行复制、更改、修改、挂接运行或创作任何衍生作品,形式包括但不限于使用插件、外挂或非经授权的第三方工具/服务接入本软件和相关系统。如果需要进行商业性的销售、复制和散发,例如软件预装和捆绑,必须获得良闯的书面授权和许可。</p>
<p>2.3 用户不得未经良闯许可,将本软件安装在未经良闯明示许可的其他终端设备上,包括但不限于电视、数字机顶盒、游戏机等装置。</p>
<p>2.4 除本协议明示授权外,良闯未授权给用户其他权利,若用户使用其他权利时须另外取得良闯的书面同意。</p>
<h2>三、软件升级</h2>
<p>3.1 用户必须选择适合所安装之终端设置的软件版本。否则,任何软件版本与装置机型不适合所引起的软件问题、装置问题或损坏,应完全由用户自行负责。</p>
<p>3.2 为了改善用户体验、完善服务内容,良闯有权不时地为您提供本软件替换、修改、升级版本,本软件为用户默认开通"升级提示"功能,视用户使用的软件版本差异,良闯提供给用户自行选择是否需要开通此功能。软件新版本发布后,良闯不保证旧版本软件的继续可用。</p>
<h2>四、使用规范</h2>
<p>4.1 用户在遵守法律及本协议的前提下可依本协议使用本软件及服务,用户不得实施如下行为:</p>
<p class="indent">4.1.1 删除本软件及其他副本上一切关于版权的信息,以及修改、删除或避开本软件为保护知识产权而设置的技术措施。</p>
<p class="indent">4.1.2 对本软件进行反向工程,如反汇编、反编译或者其他试图获得本软件的源代码。</p>
<p class="indent">4.1.3 通过修改或伪造软件运行中的指令、数据,增加、删减、变动软件的功能或运行效果,或者将用于上述用途的软件、方法进行运营或向公众传播,无论这些行为是否为商业目的。</p>
<p class="indent">4.1.4 使用本软件进行任何危害网络安全的行为,包括但不限于:使用未经许可的数据或进入未经许可的服务器/账户;未经允许进入公众网络或者他人操作系统并删除、修改、增加存储信息;未经许可企图探查、扫描、测试本软件的系统或网络的弱点或其它实施破坏网络安全的行为;企图干涉、破坏本软件系统或网站的正常运行,故意传播恶意程序或病毒以及其他破坏干扰正常网络信息服务的行为;伪造 TCP/IP 数据包名称或部分名称。</p>
<p class="indent">4.1.6 未经良闯书面同意,用户对软件及其中的信息擅自实施包括但不限于下列行为:使用、出租、出借、复制、修改、链接、转载、汇编、发表、出版,建立镜像站点、擅自借助本软件发展与之有关的衍生产品、作品、服务、插件、外挂、兼容、互联等。</p>
<p class="indent">4.1.7 利用本软件发表、传送、传播、储存违反您当地法律的内容。</p>
<p class="indent">4.1.8 利用本软件发表、传送、传播、储存侵害他人知识产权、商业秘密等合法权利的内容。</p>
<p class="indent">4.1.9 利用本软件批量发表、传送、传播广告信息及垃圾信息。</p>
<p class="indent">4.1.10 其他以任何不合法的方式、为任何不合法的目的、或以任何与本协议许可使用不一致的方式使用本软件和良闯提供的其他服务。</p>
<p>4.2 信息发布规范</p>
<p class="indent">4.2.1 您使用本软件发表信息内容的(如有),您应保证,您拥有您所上传信息内容的知识产权或已获得合法授权,您使用本软件及服务的任何行为未侵犯任何第三方之合法权益。</p>
<p class="indent">4.2.2 用户在使用本软件时不得利用本软件从事以下行为,包括但不限于:</p>
<p class="indent">4.2.2.1 制作、复制、发布、传播、储存违反当地国家法律法规的内容。</p>
<p class="indent">4.2.2.2 发布、传送、传播、储存侵害他人名誉权、肖像权、知识产权、商业秘密等合法权利的内容。</p>
<p class="indent">4.2.2.3 虚构事实、隐瞒真相以误导、欺骗他人。</p>
<p class="indent">4.2.2.4 发表、传送、传播广告信息及垃圾信息。</p>
<p class="indent">4.2.2.5 从事其他违反当地法律法规的其他行为。</p>
<p class="indent">4.2.3 未经良闯许可,您不得在本软件中进行任何诸如发布广告、销售商品的商业行为。</p>
<p>4.3 用户理解并同意:</p>
<p class="indent">4.3.1 良闯会对用户是否涉嫌违反上述使用规范做出认定,并根据认定结果中止、终止对您的使用许可或采取其他依本约定可采取的限制措施。</p>
<p class="indent">4.3.2 对于用户使用许可软件时发布的涉嫌违法或涉嫌侵犯他人合法权利或违反本协议的信息,良闯会直接删除。</p>
<p class="indent">4.3.3 对于用户违反上述使用规范的行为对第三方造成损害的,您需要以自己的名义独立承担法律责任,并应确保良闯免于因此产生损失或增加费用。</p>
<p class="indent">4.3.4 若用户违反有关法律规定或协议约定,使良闯遭受损失,或受到第三方的索赔,或受到行政管理机关的处罚,用户应当赔偿良闯因此造成的损失和(或)发生的费用,包括合理的律师费、调查取证费用。</p>
<h2>五、第三方服务说明</h2>
<p>5.1 用户理解并同意,本软件系统可能包含由良闯的关联方或第三方提供的服务,良闯只是为了用户便利操作而在系统中提供相关功能模块,提供第三方服务的使用入口。</p>
<p>5.2 不论第三方服务预置于本软件系统服务中,还是由用户自行开通或订购,用户均理解并同意,良闯不对第三方服务提供方或用户行为的合法性、有效性,以及第三方服务的合法性、准确性、有效性、安全性进行任何明示或默示的保证或担保。</p>
<p>5.3 良闯并不监督第三方服务,不对其拥有任何控制权,也不对第三方服务提供任何形式的保证或担保,更不承担任何责任。</p>
<p>5.4 用户与第三方服务提供方之间发生的任何争议、纠纷应由用户与该方按照第三方服务提供方的业务流程及业务规范自行协商解决,良闯不承担任何责任。</p>
<h2>六、隐私政策与个人信息保护</h2>
<p>6.1 良闯承诺按照隐私政策保护用户的隐私,具体请见:《Voitrans应用隐私政策》。</p>
<h2>七、违约责任</h2>
<p>7.1 良闯有权判断用户的行为是否符合本协议条款规定,如果认为用户违反有关法律法规或者本协议、相关规则的规定,根据用户违规情形的严重程度,良闯有权对用户采取删除违规信息、限制、中止、终止用户使用本软件服务、追究用户的法律责任以及其他良闯认为适合的处理措施。如果使良闯遭受任何损失(包括但不限于收到任何第三方的索赔或任何行政管理部门的处罚),用户应当承担全部责任。</p>
<h2>八、服务风险及免责声明</h2>
<p>8.1 良闯以目前的技术提供服务支持。良闯不保证本软件服务在操作上不会中断或没有错误,不保证会纠正本软件服务的所有缺陷,亦不保证本软件服务能满足用户的所有要求。由此产生的后果,良闯不承担任何责任。</p>
<p>8.2 用户因第三方如通讯线路故障、技术问题、网络、电脑终端设备故障、系统不稳定性及其他各种不可抗力原因而遭受的一切损失,良闯不承担责任。</p>
<p>8.3 良闯不保证通过本软件获得的信息内容(包括但不限于调用的第三方服务内容)的合法性、真实性、准确性、有效性,良闯不对用户基于查询、查看做出的任何行为的结果承担任何责任。</p>
<p>8.4 本软件同大多数互联网软件一样,受包括但不限于用户原因、网络服务质量、社会环境等因素的差异影响,可能受到各种安全问题的侵扰,如他人利用用户的资料,造成现实生活中的骚扰;用户下载安装的其他软件或访问的其他网站中含有"特洛伊木马"等病毒,威胁到用户的终端设备信息和数据的安全,继而影响本软件的正常使用等等。用户应加强信息安全及使用者资料的保护意识,要注意加强密码保护,以免遭致损失和骚扰。</p>
<p>8.5 因用户使用本软件或要求良闯提供特定服务时,本软件可能会调用第三方系统或第三方软件支持用户的使用或访问,使用或访问的结果由该第三方提供,用户除遵守本协议相关规则外,还应遵守第三方的协议、相关规则。用户须理解并同意,在使用第三方服务时,第三方可能会对用户数据进行读取,良闯不保证通过第三方系统或第三方软件支持实现的结果的安全性、准确性、有效性及其他不确定的风险,用户应审慎判断,由此若引发的任何争议及损害,良闯不承担任何责任。</p>
<p>8.6 良闯特别提请用户注意,良闯为了保障公司业务发展和调整的自主权,良闯采取合理的方式通知用户后可随时修改或中断服务。</p>
<p>8.7 除法律法规有明确规定外,良闯将尽最大努力确保软件及其所涉及的技术及信息安全、有效、准确、可靠,但受限于现有技术,用户理解良闯不能对此进行担保。</p>
<p>8.8 由于用户因下述任一情况所引起或与此有关的人身伤害或附带的、间接的经济损害赔偿,包括但不限于利润损失、资料损失、业务中断的损害赔偿或其他商业损害赔偿或损失,需由用户自行承担:</p>
<p class="indent">(1)使用或未能使用许可软件。</p>
<p class="indent">(2)第三方未经许可的使用软件或更改用户的数据。</p>
<p class="indent">(3)用户使用软件进行的行为产生的费用及损失。</p>
<p class="indent">(4)用户对软件的误解。</p>
<p class="indent">(5)非因良闯的原因引起的与软件有关的其他损失。</p>
<p>8.9 用户同意良闯有权基于司法、监管部门、监督机构的要求或自身业务原因,暂停、中断或终止向用户提供全部或者部分本服务。对此良闯不承担任何责任。</p>
<p>8.10 用户理解并同意,良闯将会尽其商业上的合理努力保障用户在本软件及服务中的数据存储安全,但良闯不能提供完全保证,用户须理解,良闯不对服务中的数据的删除或储存或备份失败负责。</p>
<p>8.11 在法律允许的最大范围内,开发者或供应商不对因使用应用程序而造成的任何直接、间接、偶然、特殊或后果性的损害负责。用户如有进一步的需要,请去往正规医院进行深度检测。</p>
<h2>九、知识产权声明</h2>
<p>9.1 良闯是本软件的知识产权权利人。本软件的一切著作权、商标权、专利权、商业秘密等知识产权,以及与本软件相关的所有信息内容(包括但不限于文字、图片、音频、视频、图表、界面设计、版面框架、有关数据或电子文档等)均受当地法律法规和相应的国际条约保护,良闯享有上述知识产权。</p>
<p>9.2 未经良闯书面同意,用户不得为任何商业或非商业目的自行或许可任何第三方实施、利用、转让上述知识产权,良闯保留追究上述行为法律责任的权利。</p>
<h2>十、协议变更</h2>
<p>10.1 良闯有权在必要时修改本协议条款,协议条款一旦发生变动,将会在相关页面上公布修改后的协议条款。如果不同意所改动的内容,用户应主动取消此项服务。如果用户继续使用服务,则视为接受协议条款的变动。</p>
<p>10.2 良闯有权按需要修改或变更所提供的收费服务、收费标准、收费方式、服务费及服务条款。良闯在提供服务时,可能现在或日后对部分服务的用户开始收取一定的费用如用户拒绝支付该等费用,则不能在收费开始后继续使用相关的服务。</p>
</body>
</html>

151
doc/yhxy_en.html

@ -0,0 +1,151 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Voitrans Application User Protocol</title>
<style>
body {
font-family: "Calibri", "Segoe UI", "Roboto", "Helvetica Neue", Arial, sans-serif;
line-height: 1.6;
color: #333;
margin: 0;
padding: 0;
background-color: #fff;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px 40px;
}
.header-info {
text-align: right;
font-size: 14px;
color: #888;
margin-bottom: 30px;
}
h2 {
font-size: 22px;
font-weight: bold;
text-align: center;
margin-bottom: 24px;
color: #333;
}
h3 {
font-size: 18px;
font-weight: bold;
margin-top: 24px;
margin-bottom: 12px;
color: #333;
}
p {
margin-bottom: 12px;
text-align: justify;
font-size: 14px;
}
/* Responsive adjustments */
@media (max-width: 600px) {
.container {
padding: 15px;
}
h2 {
font-size: 20px;
}
h3 {
font-size: 16px;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header-info">English(US)</div>
<h2>Voitrans Application User Protocol</h2>
<p>These Terms and Conditions of Use tell you how to access using the Voitrans Application and online services (the "Services"). Saitong Industries Inc. (hereinafter referred to as "Saitong") hereby reminds users to carefully read and fully understand this User Agreement (hereinafter referred to as the "Agreement"). Users should carefully read and fully understand the terms of this Agreement. Please read carefully and choose to accept or not accept this Agreement. Your use of Voitrans APP (hereinafter referred to as "the APP" or" the Software ") will be deemed as acceptance of this Agreement and you agree to be bound by the terms of this Agreement. If you do not agree to this Agreement, do not use the APP.</p>
<p>Saitong reserves the right to amend this Agreement, and the updated terms of the Agreement will be published in this APP, effective from the date of publication.</p>
<h3>1. General rules</h3>
<p>1.1 This APP is the software provided by Saitong for connecting the headset products released by Saitong and its partner companies. The ownership and operation rights of the software and related services are all owned by Saitong.</p>
<p>1.2 This Agreement is an agreement between you (hereinafter referred to as the "User") and the company and its partners and operating partners (hereinafter referred to as the "Partners") regarding the user's use of the APP and related services.</p>
<p>1.3 The Software and services include:</p>
<p>1.3.1 The software provided provides Voitrans users with Voitrans connection and binding, function setting management and other software services, subject to the actual software services provided by the APP.</p>
<p>1.3.2 Updates, upgrades and other services of the software.</p>
<h3>2. Scope of software license</h3>
<p>2.1 We grant the user a personal, non-transferable, non-sublicensable, and non-exclusive license to the Software.</p>
<p>2.2 Users can install, use, display and run the software on a single mobile terminal device for non-commercial purposes. However, the user shall not install, use or run the software for commercial operation purposes, copy, change, modify, connect or run the software or the data released into the memory of any terminal device during the operation of the software or the interaction data between the client and the server during the operation of the software, or create any derivative works. This includes, but is not limited to, the use of plug-ins, plug-ins, or unauthorized third-party tools/services to access the Software and related systems. For commercial sale, reproduction and distribution, such as software pre-installation and bundling, written authorization and permission must be obtained from the idea.</p>
<p>2.3 The User shall not install the Software on other terminal devices without the express permission of the Creator, including but not limited to TVS, digital set-top boxes, game consoles and other devices.</p>
<p>2.4 Except as expressly authorized by this Agreement, no other rights are granted to the User, and the User shall obtain the written consent of the User to use other rights.</p>
<h3>3. Software upgrade</h3>
<p>3.1 The user must select the software version suitable for the setup of the installed terminal. Otherwise, software problems, device problems or damage caused by any software version not suitable for the device type shall be solely the responsibility of the user.</p>
<p>3.2 In order to improve the user experience and improve the service content, Saitong has the right to provide you with replacement, modification and upgrade versions of the software from time to time. The "Upgrade prompt" function is enabled for users by default. Depending on the different software versions used by users, Saitong provides users with the option to activate this function. After the release of a new version of the software, Saitong does not guarantee the continued availability of the old version of the software.</p>
<h3>4. Usage specification</h3>
<p>4.1 Users may use the Software and Services in accordance with this Agreement under the premise of abiding by the law and this Agreement, and users shall not perform the following acts:</p>
<p>4.1.1 Delete all copyright information on the Software and other copies, and modify, delete or circumvent the technical measures set up by the Software to protect intellectual property rights.</p>
<p>4.1.2 Reverse engineering the Software, such as disassembly, decompilation, or other attempts to obtain the source code of the Software.</p>
<p>4.1.3 By modifying or falsifying instructions and data in the operation of the software, increasing, deleting or changing the function or operation effect of the software, or software or methods to be used for the above purposes to operate or disseminate to the public, regardless of whether these acts are for commercial purposes.</p>
<p>4.1.4 Use the software for any behavior that jeopardizes network security, including but not limited to: using unauthorized data or accessing unauthorized servers/accounts; Access public networks or other operating systems without permission and delete, modify or add stored information; Unauthorized attempts to probe, scan, or test the weaknesses of the system or network of the software or other acts that undermine network security; Attempts to interfere with or destroy the normal operation of the software system or website, intentionally spread malicious programs or viruses, and other acts that disrupt normal network information services; Forge TCP/IP packet names or partial names.</p>
<p>4.1.6 Without the written consent of the Company, the user arbitrarily performs the following acts on the software and the information in it, including but not limited to: using, renting, lending, copying, modifying, linking, reprinting, compiling, publishing, publishing, establishing mirror sites, developing derivative products, works, services, plug-ins, plug-ins, compatibility, interconnection, etc., with the help of the Software.</p>
<p>4.1.7 Use the Software to publish, transmit, distribute, and store content that violates your local laws.</p>
<p>4.1.8 Use the software to publish, transmit, disseminate, and store content that infringes others' intellectual property rights, trade secrets, and other legitimate rights.</p>
<p>4.1.9 Use this software to publish, transmit and disseminate advertising information and junk information in bulk.</p>
<p>4.1.10 Use the Software and other Services in any unlawful manner, for any unlawful purpose, or in any manner inconsistent with the licensed use of this Agreement.</p>
<p>4.2 Information release specification</p>
<p>4.2.1 If you use the software to publish information content (if any), you should guarantee that you own the intellectual property rights of the information content uploaded by you or have obtained legal authorization, and any behavior of you using the software and services does not infringe on the legitimate rights and interests of any third party.</p>
<p>4.2.2 When using the Software, the user shall not use the Software to engage in the following activities, including but not limited to:</p>
<p>4.2.2.1 Create, copy, publish, disseminate, and store content that violates local national laws and regulations.</p>
<p>4.2.2.2 Publish, transmit, disseminate, and store content that infringes others' legal rights such as reputation, portrait, intellectual property, and trade secrets.</p>
<p>4.2.2.3 Fabricate facts, conceal the truth in order to mislead or deceive others.</p>
<p>4.2.2.4 Publish, transmit and disseminate advertising information and junk information.</p>
<p>4.2.2.5 Engaging in other acts in violation of local laws and regulations.</p>
<p>4.2.3 You may not carry out any commercial activities such as advertising and selling goods in the Software without the permission of the Company.</p>
<p>4.3 The User understands and agrees that:</p>
<p>4.3.1 Saitong will determine whether the user is suspected of violating the above specifications of use, and according to the results of the determination, suspend or terminate your license to use or take other restrictive measures that can be taken in accordance with this agreement.</p>
<p>4.3.2 For the user's use of the licensed software published suspected of illegal or suspected infringement of the legal rights of others or violation of this Agreement, the information will be directly deleted.</p>
<p>4.3.3 If the user's violation of the above rules of use causes damage to third parties, you need to bear legal responsibility independently in your own name, and you should ensure that the idea is free from losses or increased costs.</p>
<p>4.3.4 If the user violates the relevant legal provisions or agreements, causing the Saitong to suffer losses, or is subject to third-party claims, or is punished by the administrative authority, the user shall compensate the loss and/or expenses caused by the Saitong, including reasonable attorney fees, investigation and evidence collection costs.</p>
<h3>5. Third-party service description</h3>
<p>5.1 The user understands and agrees that the software system may contain services provided by affiliates of the Company or third parties, and that the Company only provides relevant functional modules in the system for the convenience of users and provides access to third-party services.</p>
<p>5.2 Whether the third-party services are preset in the software system services, or are opened or ordered by users themselves, users understand and agree that Saitong does not make any express or implied guarantee or guarantee of the legality and effectiveness of the third-party service providers or users, as well as the legality, accuracy, effectiveness and security of the third-party services.</p>
<p>5.3 The company does not supervise, control or provide any warranty or guarantee of any kind for, or assume any liability for, third party services.</p>
<p>5.4 Any dispute or dispute between the user and the third party service provider shall be resolved by the User and the third party in accordance with the business process and business norms of the third party service provider, and the company shall not assume any responsibility.</p>
<h3>6. Privacy Policy and Protection of Personal Information</h3>
<p>6.1 Saitong is committed to protecting the privacy of users in accordance with the privacy policy, please see: Voitrans applies Privacy Policy.</p>
<h3>7. Liability for breach</h3>
<p>7.1 Saitong has the right to judge whether the user's behavior complies with the provisions of this Agreement. If it is believed that the User has violated relevant laws and regulations or the provisions of this Agreement and relevant rules, according to the severity of the user's violation, Saitong has the right to delete the illegal information, restrict, suspend, terminate the user's use of the Software service, pursue the user's legal liability and take other measures that Saitong deems appropriate. If we suffer any loss (including but not limited to receiving any third party claims or penalties from any administrative department), the User shall be fully liable.</p>
<h3>8. Service Risks and Disclaimers</h3>
<p>8.1 We want to provide service support with current technology. Saitong does not warrant that the Software Service will operate without interruption or error, that all defects of the Software Service will be corrected, or that the Software Service will meet all requirements of users. The resulting consequences, the Saitong does not assume any responsibility.</p>
<p>8.2 All losses suffered by the user due to third parties such as communication line failure, technical problems, network, computer terminal equipment failure, system instability and other force majeure causes shall not be held liable.</p>
<p>8.3 Saitong does not guarantee the legality, authenticity, accuracy and effectiveness of the information content obtained through the software (including but not limited to the third party service content), and Saitong does not assume any responsibility for the results of any behavior made by users based on query and viewing.</p>
<p>8.4 The software, like most Internet software, is affected by differences in factors including but not limited to user reasons, network service quality, social environment and other factors, and may be subjected to various security problems, such as others using user information, resulting in harassment in real life; Other software downloaded and installed by users or other websites visited by users contain viruses such as "Trojan horses", which threaten the security of users' terminal equipment information and data, and then affect the normal use of the software. Users should strengthen the awareness of information security and user data protection, and pay attention to strengthen password protection to avoid loss and harassment.</p>
<p>8.5 When users use the Software or require Saitong to provide specific services, the Software may call third-party systems or third-party software to support users' use or access, and the results of use or access are provided by the third party. In addition to complying with the relevant rules of this Agreement, users shall also comply with the agreements and relevant rules of the third party. Users must understand and agree that, when using third-party services, third parties may read user data, and Saitong does not guarantee the safety, accuracy, effectiveness and other uncertain risks of the results achieved through third-party systems or third-party software support, users should exercise careful judgment, and Saitong does not assume any responsibility for any disputes and damages caused by this.</p>
<p>8.6 In order to guarantee the autonomy of the company's business development and adjustment, the company may modify or interrupt the service at any time after taking a reasonable way to notify the user.</p>
<p>8.7 Except as expressly provided by laws and regulations, Saitong will make its best efforts to ensure that the software and the technology and information involved are safe, effective, accurate and reliable, but limited by the existing technology, the user understands that Saitong cannot guarantee this.</p>
<p>8.8 Compensation for personal injury or incidental and indirect economic damage caused by or in connection with any of the following circumstances, including but not limited to loss of profits, loss of data, damages for business interruption or other business damages or losses, shall be borne by the User:</p>
<p>1) Use or failure to use the licensed software.</p>
<p>2) Unauthorized use of the software or alteration of user data by third parties.</p>
<p>3) Expenses and losses incurred by the user's actions with the software.</p>
<p>4) User misconceptions about the software.</p>
<p>5) Any other loss related to the software that is not attributable to Saitong causes.</p>
<p>8.9 The User agrees that the Company has the right to suspend, interrupt or terminate all or part of the Service to the user based on the requirements of the judicial, regulatory and supervisory authorities or its own business reasons. Saitong accepts no responsibility for this.</p>
<p>8.10 The User understands and agrees that the Company will use its commercially reasonable efforts to ensure the security of data storage in the Software and Services, but the company cannot provide a complete guarantee, and the User understands that the Company is not responsible for the deletion or storage or backup failure of data in the Service.</p>
<p>8.11 To the fullest extent permitted by law, the Developer or Supplier shall not be liable for any direct, indirect, incidental, special or consequential damages arising from the use of the Application. If the user has further needs, please go to the regular hospital for in-depth testing.</p>
<h3>9. Intellectual property statement</h3>
<p>9.1 Saitong is the intellectual property right holder of this software. All Copyrights, trademarks, patents, trade secrets and other intellectual property rights of the software, as well as all information content related to the software (including but not limited to text, pictures, audio, video, graphics, interface design, layout frame, relevant data or electronic documents, etc.) are protected by local laws and regulations and corresponding international treaties.</p>
<p>9.2 Without the written consent of the Company, the User shall not implement, utilize or transfer the above intellectual property rights for any commercial or non-commercial purpose, or permit any third party, and the Company reserves the right to pursue the legal responsibility for the above acts.</p>
<h3>10. Protocol change</h3>
<p>10.1 Saitong has the right to modify the terms of this Agreement when necessary. Once the terms of the Agreement are changed, the revised terms of the Agreement will be published on the relevant page. If you do not agree with the changed content, the user should take the initiative to cancel this service. If the User continues to use the Services, it is deemed to accept the changes in the terms of the Agreement.</p>
<p>10.2 Saitong reserves the right to modify or change the paid services, charging standards, charging methods, service fees and terms of service provided as necessary. When providing services, we may charge certain fees to users of some services now or in the future. If users refuse to pay such fees, they cannot continue to use the relevant services after the start of the fees.</p>
</div>
</body>
</html>

397
doc/ysxy.html

@ -0,0 +1,397 @@
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>Voitrans隐私政策</title>
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
line-height: 1.6;
margin: 0;
padding: 16px;
color: #2d2d2d;
background-color: #fafafa;
overflow-x: hidden;
word-wrap: break-word;
word-break: break-all;
}
@media (min-width: 768px) {
body {
max-width: 900px;
margin: 0 auto;
padding: 20px 40px;
}
}
h1 {
text-align: center;
font-size: 28px;
margin-top: 20px;
font-weight: bold;
}
h2 {
font-size: 24px;
margin-top: 18px;
font-weight: bold;
}
h3 {
font-size: 20px;
margin-top: 16px;
font-weight: bold;
}
h4 {
font-size: 16px;
margin-top: 12px;
font-weight: bold;
color: #555;
}
p {
margin-bottom: 1em;
text-align: justify;
word-wrap: break-word;
word-break: break-all;
}
ul {
margin-bottom: 1em;
padding-left: 20px;
}
ul li {
margin-bottom: 0.5em;
}
</style>
</head>
<body>
<h1>Voitrans 隐私政策</h1>
<p>更新日期:2025年5月27日</p>
<p>生效日期:2025年5月27日</p>
<p>深圳市良闯时代科技有限公司(下称“我们”),是VoitransAPP(具体范围及定义见下文)的开发者和运营者。我们深知个人信息对您的重要性,您的信任对我们非常重要,我们将按照法律法规的规定并参照行业最佳实践保护您的个人信息及隐私安全。我们制定本"隐私政策"并特别提示:希望您在使用Voitrans及相关服务前仔细阅读并理解本隐私政策,以便做出适当的选择。
</p>
<p>本隐私政策将帮助您了解 :</p>
<p>我们会遵循隐私政策收集、使用您的信息,但不会仅因您同意本隐私政策而采用强制捆绑的方式收集个人信息。</p>
<p>当您使用或开启相关功能或使用服务时,为实现功能、服务所必需,我们会收集、使用相关信息。除非是为实现业务功能或根据法律法规要求所必需的必要信息,您均可以拒绝提供且不影响其他功能或服务。我们将在隐私政策中逐项说明所要收集的信息。
</p>
<p>如果您未登录账号,我们会通过设备对应的标识符信息来保障信息推送的基本功能。如果您登录了账号,我们会根据账号信息实现信息推送。</p>
<p>精确地理位置、摄像头(相机)、相册(存储)等权限,均不会默认开启,只有经过您的明示授权才会在为实现特定功能或服务时使用,您也可以撤回授权。特别需要指出的是,即使经过您的授权,我们获得了这些敏感权限,也不会在相关功能或服务不需要时而收集您的信息。
</p>
<p>下文将帮您详细了解我们如何收集、使用、存储、转移(如适用)与保护个人信息;帮您了解查阅、复制、更正、删除、撤回授权个人信息的方式。本政策与您使用我们的服务关系密切,我们建议您仔细阅读并理解本政策全部内容,作出您认为适当的选择,有关您个人信息权益的条款重要内容我们已用加粗形式提示
, 请特别关注。</p>
<p>1.我们如何收集和使用个人信息</p>
<p>2 .数据使用过程中涉及的合作方以及转移、公开个人信息</p>
<p>3 .我们如何存储个人信息</p>
<p>4 .我们如何保护个人信息的安全</p>
<p>5 .我们如何管理您的个人信息</p>
<p>6 .未成年人条款</p>
<p>7 .隐私政策的修订和通知</p>
<p>8 .联系我们</p>
<h2>1. 我们如何收集和使用个人信息</h2>
<p>我们会按照如下方式收集您在访问Voitrans平台或使用Voitrans平台提供的产品及服务时主动提供的,以及通过自动化手段收集您在使用功能或接受服务过程中产生的信息,收集和使用这些信息的目的和用途详见下述功能描述部分。
</p>
<p>我们不会通过共享、转让、搜集公开信息等其他渠道间接获取有关您的个人信息。如将来发生需通过其他渠道间接获取您的个人信息时,我们只获取实现产品或服务的业务功能所必需的最少数量的信息,且在收集和使用之前明确告知您并征求您的明示同意。同时,我们将在收集信息前确保信息来源的合法性,了解个人信息提供方已获得的个人信息处理的授权同意范围,包括使用目的、授权同意转让、共享、公开披露等。若我们开展业务需进行的个人信息处理活动超出该授权同意范围,会在获取个人信息后的合理期限内或处理个人信息前,征得您的明示同意。
</p>
<p>我们收集和使用您的信息的目的和用途详情如下:</p>
<h3>1.1 注册、登录Voitrans</h3>
<p>当您注册、登录Voitrans时,您可以通过手机号,电子邮箱,以及微信授权方式,创建“Voitrans账号”,并且完善相关的网络身份识别信息(账号、密码、头像、昵称),我们会收集您的手机号,并且获取短信验证码,以便我们对您的账户进行身份核验。
</p>
<p>收集您的上述信息是为了帮助您完成手机号注册和登陆,保证您的账户权益。此类信息属于使用手机号注册和登录的必要信息,如您不提供将无法完成注册/登录操作。</p>
<h3>1.2 录音</h3>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.2.1 必要信息范围</h4>
<p>在您联网使用录音功能服务时,我们将收集您的语音信息与/或您提供的其他录音内容 。此类信息属于录音功能服务的必要信息 。请您知悉,在未联网的环境下或您未主动上传的情况下,前述信息仅会存储在设备端
,我们不会收集并上传云端服务器存储。</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.2.2 调用的权限范围</h4>
<p>在您使用录音功能服务时,我们需要调用您的麦克风权限以获取您的语音信息,此为该功能服务所必须的系统权限,若您拒绝,您将无法使用录音功能 。</p>
<p>在您使用录音存储功能服务时,我们需要调用您的存储权限以存储您的语音信息,此为该功能服务所必须的系统权限,若您拒绝,您将无法使用录音功能 。</p>
<h3>1.3 语音转写</h3>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.3.1 必要信息范围</h4>
<p>在您使用语音转文字功能服务时,我们将收集您的语音信息与/或您提供的其他录音内容以在云端服务器进行语音转写。同时,我们会收集转写后的文本信息
,判断您的需求并做出实时处理反馈给您,以方便您了解进行了哪些语音交互。此类信息属于语音转文字功能的必要信息,如您不能提供,您将无法使用语音转文字功能。</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.3.2 调用的权限范围</h4>
<p>在您使用语音转文字功能服务时,我们需要调用您的麦克风权限以获取您的语音信息,此为该功能服务所必须的系统权限,若您拒绝,您将无法使用语音转文字功能。</p>
<h3>1.4 管理录音及转写文稿</h3>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.4.1 必要信息范围</h4>
<p>当您在登录状态下使用录音转文字功能,并对以及转写文稿进行云端存储、编辑、管理时,我们将收集您的录音以及编辑后的转写文稿信息,如文本信息、语音信息,同时需获取您的网络状态,在您允许我们开启存储与网络权限后,我们可以获取到您的录音以及编辑后的转写文稿信息
,这是为了方便您随时导出、存储、分享您的录音以及编辑后的转写文稿。此类信息属于云端存储、编辑与管理录音及转写文稿必须的信息,如您拒绝提供,我们将无法为您提供云端存储、编辑、管理、分享、下载等服务,但不影响您使用本软件的其他功能。
</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.4.2 调用的权限范围</h4>
<p>在您修改录音文件时,我们需要调用您的存储权限以存储您的文本信息 ,此为该功能服务所必须的系统权限,若您拒绝,您修改后的内容将不会存储至本地端。</p>
<h3>1.5 语音翻译</h3>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.5.1 必要信息、非必要信息范围</h4>
<p>若您使用语音翻译服务,我们会申请您设备系统的麦克风权限、存储权限 。在经您授权同意后,我们会收集您的语音信息
,以便/以用于获取说出的语音来进行翻译。此类信息属于语音转文字功能的必要信息,如您不能提供,您将无法使用语音翻译功能。</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.5.2 调用的权限范围</h4>
<p>在您使用语音翻译和同声传译功能服务时我们需要调用您的麦克风权限以获取您的语音信息 ,此为该功能服务所必须的系统权限,若您拒绝,您将无法使用语音翻译和同声传译功能。</p>
<p>同时,我们需要调用您的存储权限以存储您的语音信息和文本信息,此为该功能服务所必须的系统权限,若您拒绝,您将无法使用语音翻译功能。</p>
<h3>1.7 设备权限</h3>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.7.1 位置权限</h4>
<p>在使用智能翻译功能时,我们将收集您的定位信息以获得您的精确地理位置信息,用于实现智能翻译中的自动检测源语言功能,我们将根据您的定位信息自动匹配出您使用的语言,向您提供智能翻译服务。精确地理位置信息是个人敏感信息,若您拒绝开启GPS权限,我们将无法为您自动匹配翻译语言,需要您手动进行语言的选择。
</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.7.2 蓝牙权限</h4>
<p>在您连接智能硬件时,我们需要获取您的蓝牙权限来搜索设备,传输配网信息,实现绑定设备目的。</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.7.3 通讯录权限</h4>
<p>在您使用拨打电话功能时,我们需要获取您的通讯录权限获取信息,实现您给对应用户拨打电话的需求。</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.7.4 短信权限</h4>
<p>在您使用智能助手时,我们需要获取您的短信权限,实现您给对应用户发送短信的需求。</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.7.5 系统通知权限</h4>
<p>在向您推送 PUSH 消息时,我们需要获取您的通知权限。这是为了能在您的设备通知栏显示 APP 相关的通知内容,包括但不限于 APP
的新功能上线通知、您关注内容的更新信息、优惠活动提醒等。若您拒绝开启通知权限,您将无法及时收到这些重要信息,可能会错过 APP 为您准备的精彩内容和便利服务。</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.7.7 存储权限(较少情况)</h4>
<p>在某些特殊的 PUSH
消息场景下,若消息需要将一些临时数据存储在本地设备上,我们需要获取您的存储权限。比如推送包含新功能配置文件的消息,需要存储权限来保存这些文件到本地,以便实现新功能在您设备上的应用。若您拒绝此权限,相关特殊功能可能无法正常使用。
</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.7.8 相机权限</h4>
<p>当您使用设置头像或意见反馈上传图片功能时,我们会申请相机权限。在您明确授权后,相机将被用于拍摄照片以满足对应功能需求,且仅在相关功能运行期间收集和使用相机所产生的数据,功能结束后不再进行数据收集。若您拒绝授权相机权限,将无法使用涉及相机的相关功能,但不影响其他功能的正常使用。
</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.7.8.1 相机权限的使用场景</h4>
<p>在Voitrans App中,我们有两个主要功能,需要使用到您的相机权限:</p>
<p>更改个人头像:当您希望更改您的个人头像时,我们需要调用相机权限以便您能够拍摄新的照片或从相册中选择一张图片作为头像。</p>
<p>意见反馈功能:在意见反馈功能中,如果您希望通过上传图片来提供更详细的反馈信息,我们需要相机权限来允许您拍摄照片或从相册中选择图片上传。</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.7.8.2 用户控制</h4>
<p>您可以随时在设备的设置中开启或关闭相机权限。如果您选择关闭相机权限,您将无法使用上述功能,但不影响您使用Voitrans App的其他功能。</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.7.8.3 数据的存储和处理</h4>
<p>照片存储:当您使用相机权限拍摄照片或选择图片时,这些图片仅在您的设备上存储,除非您主动选择上传。</p>
<p>数据处理:如果图片被上传到我们的服务器,我们将按照隐私政策中的规定处理这些数据,包括但不限于存储、备份和删除机制。</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.7.8.4 数据的共享和转让</h4>
<p>我们不会与任何第三方共享或转让通过相机权限收集的图片数据,除非是为了提供服务所必需,或者您明确同意。</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.7.8.5 用户撤销权限后的影响</h4>
<p>如果您撤销相机权限,您将无法使用更改个人头像和意见反馈中上传图片的功能。如果您希望重新授权,可以在设备的设置中重新开启相机权限。</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.7.8.6 相机权限的安全性</h4>
<p>我们承诺采取行业标准的安全措施来保护您通过相机权限提供的数据,包括但不限于数据加密传输和安全存储。</p>
<h3>1.8 用户反馈与服务</h3>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.8.1客服及问题</h4>
<p>为便于与您联系、尽快帮助您解决问题或记录相关问题的处理方案及结果,我们可能会保存您与我们的通信/通话记录及相关内容(包括账号信息、反馈信息、预约信息、您为了证明相关事实提供的其他信息,或您留下的联系方式信息),如果您针对具体预约进行咨询、投诉或提供建议的,我们会使用您的账号信息和预约信息。
</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.8.2 投诉</h4>
<p>当您投诉他人或被他人投诉时,为了保护您及他人的合法权益,我们可能会将您的账号/身份信息、联系方式、投诉相关内容提供给消费者权益保护部门及监管机关,以便及时解决投诉纠纷,但法律法规明确禁止提供的除外。</p>
<p>如您通过我们产品或服务使用良闯时代关联方、合作方提供的服务并进行投诉时,为便于服务提供方(如良闯时代关联方、合作方)能与您有效联系并及时处理您的投诉,您同意我们获取您投诉时所提供的个人信息,并同步给对应服务提供方。</p>
<h3>1.9 运营与安全运行/保障</h3>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.9.1 运营与安全保障</h4>
<p>我们致力于为您提供安全、可信的产品与使用环境,提供优质而可靠的服务与信息是我们的核心目标。为了维护Voitrans 平台的正常运行,保护您或其他用户或公众的合法利益免受损失,我们会收集用于维护产品或服务安全稳定运行的必要信息。
</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">1.9.2 设备信息与日志信息</h4>
<p>a. 为了保障软件与服务的安全运行、运营的质量及效率,我们会收集您的硬件型号、操作系统版本号、设备标识符(Android如 IMEl 、 Android_ID 、 OAID 、 IMSI 、 ICCID 、 GAID 、
MEID 、硬件序列号, iOS 如 IDFV 、 IDFA: 不同的标识符在有效期,是否可由用户重置以及获取方式方面会有所不同) 、网络设备硬件地址 (MAC 地址 ) 、 IP 地址、 WLAN 接入点 ( 如 SSID
, BSSID) 、蓝牙 (Bluetooth) 、基站、软件版本号、网络接入方式、类型、状态、网络质量数据、操作、使用、服务日志、设备传感器数据。</p>
<p>b. 为了预防恶意程序、保障运营质量及效率,我们会收集安装的应用信息或正在运行的进程信息、应用程序的总体运行、使用情况与频率。应用崩溃情况、总体安装使用情况、性能数据、应用来源。</p>
<p>c. 为了分析应用新增、激活、留存、性能等统计性指标,我们可能会调用剪切板对相关统计信息进行归因分析,请您放心,我们不会收集您的隐私信息。</p>
<p>d. 我们可能使用您的账户信息、设备信息、服务日志信息以及我们关联方、合作方在获得您授权或依法可以提供的信息,用于判断账户安全、进行身份验证、识别违法违规情况、检测及防范安全事件,并依法采取必要的记录、分析、处置措施。</p>
<p>1.10 收集、使用个人信息目的变更</p>
<p>请您了解,随着我们业务的发展,可能会对 Voitrans
的功能和提供的服务有所调整变化。原则上,当新功能或服务与我们当前提供的功能或服务相关时,收集与使用的个人信息将与原处理目的具有直接或合理关联。在与原处理目的无直接或合理关联的场景下,我们收集、使用您的个人信息,会再次按照法律法规及国家标准的要求以页面提示、交互流程、协议确认方式另行向您进行告知说明,并征得您的同意。
</p>
<h3>1.11 征得授权同意的例外</h3>
<p>请您理解,在下列情形中,根据法律法规及相关国家标准,我们收集和使用您的个人信息不必事先征得您的授权同意:</p>
<p>a. 与我们履行法律法规规定的义务相关的;</p>
<p>b. 与国家安全、国防安全直接相关的;</p>
<p>c. 与公共安全、公共卫生、重大公共利益直接相关的;</p>
<p>d. 与刑事侦查、起诉、审判和判决执行等直接相关的;</p>
<p>e. 出于维护您或他人的生命、财产等重大合法权益但又很难得到本人授权同意的;</p>
<p>f. 您自行向社会公众公开的个人信息;</p>
<p>g. 根据个人信息主体要求签订和履行合同所必需的;</p>
<p>h. 从合法公开披露的信息中收集的您的个人信息的,如合法的新闻报道、政府信息公开等渠道;</p>
<p>i. 用于维护软件及相关服务的安全稳定运行所必需的,例如发现、处置软件及相关服务的故障;</p>
<p>j. 为开展合法的新闻报道所必需的;</p>
<p>k. 为学术研究机构,基于公共利益开展统计或学术研究所必要,且对外提供学术研究或描述的结果时,对结果中所包含的个人信息进行去标识化处理的;</p>
<p>l. 法律法规规定的其他情形。</p>
<p>特别提示您注意,如信息无法单独或结合其他信息识别到您的个人身份,其不属于法律意义上您的个人信息 ;
当您的信息可以单独或结合其他信息识别到您的个人身份时或我们将无法与任何特定个人信息建立联系的数据与其他您的个人信息结合使用时,这些信息在结合使用期间,将作为您的个人信息按照本隐私政策处理与保护。</p>
<h3>1.12 人机交互对话</h3>
<p>在您使用我们的人机交互服务时(包括智能助手,等),我们会收集您主动输入的内容(包括文本、图片、音视频等),并基于这些信息为您提供相应的服务。当您使用语音输入时,我们将收集您的音频数据,进行语音转写,并基于转写后的文本生成对话内容,以提供更好的互动体验。
</p>
<p>如果您输入的信息包含他人个人数据,请确保已获得他人的合法授权,避免不当泄露他人隐私。</p>
<p>为了更好地理解您的需求和语境,我们会对您提供的信息进行分析和处理,以便输出更具相关性的内容。在确保信息经过加密、安全处理且去标识化的前提下,我们可能会将所收集的数据和生成的回复用于模型训练,持续优化服务质量。</p>
<h3>1.13 数据埋点统计及上报</h3>
<p>我们在 APP 内设置了页面埋点,目的是为了统计 APP 的使用情况,以便更好地优化产品性能、修复漏洞以及提升您的使用体验。当您访问 APP
页面时,页面埋点会收集您的页面浏览记录、点击行为、停留时长等信息,但此类信息的收集频率遵循合理必要原则,通常情况下,同一页面在您单次访问期间仅收集一次,不会对您造成频繁的数据收集干扰。仅在您进行交互操作(如点击按钮、切换页面板块等)触发新的业务需求时,才会根据实际需要再次收集与之相关的少量信息。
</p>
<p>a. 我们收集的信息将主要用于为您提供、优化和改进本 APP 的服务,依据您的反馈修复程序问题等。</p>
<p>b. 部分信息可能会用于数据分析和研究,以了解用户群体的使用习惯和偏好趋势,从而推动本 APP 的持续创新发展。</p>
<h3>1.14 模型服务与数据处理</h3>
<p>1.14.1 模型服务基础</p>
<p>Voitrans 接入了目前国内比较优秀的的人工智能大模型服务,如豆包, DeepSeek,未来会持续优化模型的接入能力,拓展更多的模型,以为用户提供更好的服务。</p>
<p>1.14.2 数据收集与共享</p>
<p>在您使用第三方模型期间,为实现高效的聊天互动、回答问题、生成图像等服务,我们会收集您的输入内容并共享给相关服务提供方,以便根据您的内容提供文生文或文生图的人机交互服务。</p>
<p>1.14.3 模型服务说明</p>
<p>在您使用第三方模型期间,如遇到问题,可及时于我们取得联系,我们将持续优化模型的接入。</p>
<h3>1.15 应用自启动与关联启动说明</h3>
<p>1.15.1 自启动用途说明</p>
<p>Voitrans app 需要使用自启动能力以确保与外部蓝牙设备(如ble蓝牙耳机)保持稳定连接,这对于提供持续的语音交互和设备控制服务是必要的。自启动功能仅用于维持蓝牙连接服务,不会进行其他后台操作。</p>
<p>1.15.2 自启动场景说明</p>
<ul>
<li>蓝牙设备连接:当配对的蓝牙设备在范围内被激活时,应用需要自动启动以建立连接。</li>
<li>设备通信维护:为确保与蓝牙设备的实时通信质量,需要保持后台服务运行。</li>
<li>语音交互响应:当用户通过蓝牙设备发起语音指令时,应用需要及时响应。</li>
<li>设备状态监控:实时监控蓝牙设备的连接状态,确保服务的可靠性。</li>
</ul>
<h2>2. 数据使用过程中涉及的合作方以及转移、公开个人信息</h2>
<h3>2.1数据使用过程中涉及的合作方</h3>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">2.1.1原则</h4>
<p>a.合法原则 :与合作方合作过程中涉及数据使用活动的,必须具有合法目的、符合法定的合法性基础。如果合作方使用信息不再符合合法原则,则其不应再使用您的个人信息,或在获得相应合法性基础后再行使用。</p>
<p>b.正当与最小必要原则 :数据使用必须具有正当目的,且应以达成目的必要为限。</p>
<p>c.安全审慎原则 :我们将审慎评估合作方使用数据的目的,对这些合作方的安全保障能力进行综合评估,并要求其遵循合作法律协议。我们会对合作方获取信息的软件工具开发包(SDK)、应用程序接口 (API)
进行严格的安全监测,以保护数据安全。</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">2.1.2委托处理</h4>
<p>对于委托处理个人信息的场景,我们会与受托合作方根据法律规定签署相关处理协议,并对其个人信息使用活动进行监督。</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">2.1.3共同处理</h4>
<p>对于共同处理个人信息的场景,我们会与合作方根据法律规定签署相关协议并约定各自的权利和义务,确保在使用相关个人信息的过程中遵守法律的相关规定、保护数据安全。</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">2.1.4合作方的范围</h4>
<p>若具体功能和场景中涉及由我们的关联方、第三方提供服务,则合作方范围包括我们的关联方与第三方。</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">2.1.5实现功能或服务的数据使用</h4>
<p>a.地理位置服务 : 当您使用地理位置相关服务时,位置服务提供商 ( 高德地图 ) 可能会通过 SDK 或相关技术使用您的 GPS
信息、设备信息以便可以向您返回位置结果。拒绝上述使用仅会影响地理位置服务功能,但不影响其他功能的正常使用。</p>
<p>b.客户服务 : 为及时处理您的投诉、建议以及其他诉求,客户服务提供商需要使用您的账号及所涉及事件的相关信息,以及时了解、处理和响应相关问题。</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">2.1.6实现安全与分析统计的数据使用</h4>
<p>a.保障使用安全 : 我们非常重视账号、服务及内容安全,为保障您和其他用户的账号与财产安全,使您和我们的正当合法权益免受不法侵害,我们的合作方可能会使用必要的设备、账号及日志信息。</p>
<p>b.分析产品情况 : 为分析我们产品的使用和表现情况,我们的合作方可能需要使用该产品使用情况(崩溃、闪退 ) 、设备标识信息、应用总体安装使用情况等信息。</p>
<p>c. 为提升相关领域的科研能力,促进科技发展水平,我们在确保数据安全与目的正当的前提下,可能会与合作的科研院所、高校等机构使用去标识化或匿名化的数据。</p>
<h3>2.2 转移</h3>
<p>随着我们业务的持续发展,我们将有可能进行合并、收购、资产转让,您的个人信息有可能因此而被转移。在发生前述变更时,我们将按照法律法规及不低于本隐私政策所载明的安全标准要求继受方继续履行个人信息处理者的义务,若继受方变更原先的处理目的、处理方式的,我们将要求继受方重新征得您的授权同意。
</p>
<h3>2.3 公开</h3>
<p>a. 我们不会公开您的信息,除非遵循国家法律法规规定或者获得您的同意。我们公开您的个人信息会采用符合行业内标准的安全保护措施。</p>
<p>b.对违规 账号 、欺诈行为进行处罚公告时,我们会披露相关账号的信息。</p>
<h3>2.4 依法豁免征得同意提供、公开的个人信息</h3>
<p>请您理解,在下列情形中,根据法律法规及国家标准,我们向合作方提供、公开您的个人信息无需征得您的授权同意 :</p>
<p>a. 为订立、履行您作为一方当事人的合同所必需,或者按照依法制定的劳动规章制度和依法签订的集体合同实施人力资源管理所必需;</p>
<p>b.为履行法定职责或者法定义务所必需 ;</p>
<p>c.与国家安全、国防安全直接相关的 ;</p>
<p>d.与刑事侦查、起诉、审判和判决执行等直接相关的 ;</p>
<p>e.为应对突发公共卫生事件,或者紧急情况下为保护自然人的生命健康和财产安全所必需 ;</p>
<p>f. 出于维护您或其他个人的生命、财产等重大合法权益但又很难得到您本人授权同意的;</p>
<p>g.为公共利益实施新闻报道、舆论监督等行为 , 在合理的范围内处理个人信息 ;</p>
<p>h.依照相关法律规定处理您自行公开或者其他已经合法公开的个人信息 ;</p>
<p>i.从合法公开披露的信息中收集个人信息的,如合法的新闻报道、政府信息公开等渠道;</p>
<p>j.法律、行政法规规定的其他情形。</p>
<h3>2.5 支付</h3>
<p>您授权我们通过指定的付款方式向您收取费用。当您使用Voitrans
app及相关服务涉及交易时,系统将会生成您的交易订单,您需要填写购买人姓名、订单相关手机号码,订单会自动生成您所购买的商品或服务信息、您应支付的货款金额及您选择的支付方式等支付信息,您可能在订单上补充告知相关方的其他信息以方便交易的实现。
</p>
<p>当您使用涉及支付的功能时:支付通过合作的第三方支付机构(微信支付苹果支付等)所提供的支付服务完成,第三方支付服务有可能使用生物识别信息用于付款验证,您在使用第三方支付服务的时候请阅读该第三方机构的用户协议、隐私政策,如对于该第三方机构的用户协议、隐私政策不同意的,请您及时停止使用该第三方机构的支付服务。
</p>
<h2>3. 我们如何存储个人信息</h2>
<h3>3.1存储地点</h3>
<p>我们依照法律法规的规定,将在境内运营过程中收集和产生的您的个人信息 存储于中华人民共和国境内。目前,我们不会将上述信息传输至境外,如果我们向境外传输,会严格遵守中国的相关法律、监管政策,并会遵循相关国家规定或者征求您的同意。
</p>
<h3>3.2 存储期限</h3>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">3.2.1 我们仅在为提供Voitrans 服务之目的所必需的期间内保留您的个人信息,例如:</h4>
<p>a. 手机号码: 当您使用手机号码注册登录时,我们需要持续保留您的手机号码,以便于向您提供正常的服务、应对您可能的查询和客诉并保障您的账号和系统安全。</p>
<p>b.电子邮箱:当您使用电子邮箱注册登录时,我们需要持续保留您的电子邮箱,以便于向您提供正常的服务、应对您可能的查询和客诉并保障您的账号和系统安全。</p>
<p>c.第三方授权:当您使用其他合作方授权方式登录时,我们会保留您的授权信息,以便您可以持续使用第三方登录方式进行登录,使得我们可以持续为您提供服务。</p>
<p>c. 您发布的信息、评论、点赞及相关信息,在您未撤回、删除或未注销账号期间,我们会保留相关信息用于向您提供持续的业务功能。</p>
<p>d. 根据《中华人民共和国网络安全法》、《中华人民共和国电子商务法》相关规定保留您的个人信息。</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">3.2.2
如果您注销账号、主动删除个人信息或超出必要的期限后,我们将对您的个人信息进行删除或匿名化处理,但以下情况除外:</h4>
<p>a .遵从法律法规有关信息留存的要求;</p>
<p>b .遵守法院判决、裁定或其他法律程序的规定;</p>
<p>c. 遵守相关政府机关或法定授权组织的要求;</p>
<p>d. 出于财务、审计、争议解决等目的需要合理延长期限的。</p>
<h2>4. 我们如何保护个人信息的安全</h2>
<h3>4.1 我们非常重视您个人信息的安全,将努力采取合理的安全措施 ( 包括技术方面和管理方面 ) 来保护您的个人信息,防止您提供的个人信息被不当使用或未经授权的情况下被访问、公开披露、使用、修改、损坏、丢失或泄漏。</h3>
<h3>4.2 我们会使用不低于行业同行的加密技术、 匿 名化处理及相关合理可行的手段保护您的个人信息,并使用安全保护机制防止您的个人信息遭到恶意攻击。</h3>
<h3>4.3 我们会建立专门的安全部门、安全管理制度、数据安全流程保障您的个人信息安全。我们采取严格的数据使用和访问制度,确保只有授权人员才可访问您的个人信息,并适时对数据和技术进行安全审计。</h3>
<h3>4.4
尽管已经采取了上述合理有效措施,并已经遵守了相关法律规定要求的标准,但请您理解,由于技术的限制以及可能存在的各种恶意手段,在互联网行业,即便竭尽所能加强安全措施,也不可能始终保证信息百分之百的安全,我们将尽力确保您提供给我们的个人信息的安全性。
</h3>
<h3>4.5 您知悉并理解,您接入我们的服务所用的系统和通讯网络,有可能因我们可控范围外的因素而出现问题。因此,我们强烈建议您采取积极措施保护个人信息的安全,包括但不限于使用复杂密码、定期修改密码、不将自己的 账号
密码及相关个人信息透露给他人。</h3>
<h3>4.6 我们会制定应急处理预案,并在发生用户信息安全事件时立即启动应急预案,努力阻止这些安全事件的影响和后果扩大。一 旦 发生用户信息安全事件(泄露、丢失 ) 后,我们将按照法律法规的要求,及时向您告知 :
安全事件的基本情况和可能的影响,我们已经采取或将要采取的处置措施、您可自主防范和降低风险的建议、对您的补救措施。我们将及时将事件相关情况以推送通知、邮件、信函、短信及相关形式告知您,难以逐一告知时,我们会采取合理、有效的方式发布公告。同时,我们还将按照相关监管部门要求,上报用户信息安全事件的处置情况。
</h3>
<h3>4.7 您一旦离开Voitrans 平台及相关服务,浏览或使用其他网站、服务及内容资源,我们将没有能力和直接义务保护您在Voitrans
平台及相关服务之外的软件、网站提交的任何个人信息,无论您登录、浏览或使用上述软件、网站是否基于Voitrans 平台的链接或引导。</h3>
<h2>5. 我们如何管理您的个人信息</h2>
<p>我们非常重视您对个人信息的管理,并尽全力保护您对于您个人信息的查阅、复制、更正、补充、删除、撤回同意授权、注销账号、投诉举报以及设置隐私功能等权利,以使您有能力保障您的隐私和信息安全。</p>
<h3>5.1 改变或撤回授权范围</h3>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">5.1.1 改变或撤回敏感权限设置 :
特定的业务功能和服务将需要您的设备敏感权限才能得以完成,当您改变或撤回敏感权限后,我们无法继续为您提供撤回敏感权限所对应的功能和服务,也不再处理您相应的敏感权限信息。但您撤回敏感权限的决定,不会影响我们此前基于您的授权而开展的个人信息处理。您可以通过
更改移动终端的设置 开启或关闭敏感权限。</h4>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">5.1.2 改变或撤回授权的信息处理 :
特定的业务功能和服务将需要您的信息才能得以完成,当您撤回同意或授权后,我们无法继续为您提供撤回同意或授权所对应的功能和服务,也不再处理您相应的个人信息。但您撤回同意或授权的决定,不会影响我们此前基于您的授权而开展的个人信息处理。
</h4>
<h3>5.2 您的个人信息权利</h3>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">5.2.1 查阅个人信息 :</h4>
<p>您可以通过Voitrans APP【个人中心】查阅您的昵称、手机号等个人信息。</p>
<h4 style="font-size: 16px; margin-top: 12px; color: #555;">5.2.2 更正个人信息 :</h4>
<p>您可以通过Voitrans APP【个人中心】修改您的昵称 等个人信息 。</p>
<p>特别提示您注意,出于安全性和身份识别(如号码申诉服务 ) 的考虑,您可能无法自主修改注册时提交的某些初始注册信息。如您确有需要修改该类注册信息,请根据本隐私政策载明的联系方式联系我们。</p>
<p>除上述外,如果您或其他有权主体对相关法律法规赋予的个人信息权利的行使,有任何主张,要求或者疑问,您可以通过我们预留的联系方式(官网、APP内)与我们联系,我们将尽快审核所涉问题,并在验证您的用户身份后的1 0 个工作日内回复。
</p>
<h3>5.3 注销 账号</h3>
<p>您可以通过Voitrans APP【设置】 -【个人中心】 - 【注销 账号 】与我们联系申请注销您的账号,我们将会在收到您的申请后及时进行处理,并在1 0
个工作日或法律法规要求的时限内回复您的请求。在您注销账号前,我们将验证您的个人身份、安全状态、设备信息等。您知悉并理解,注销账号是不可逆的行为。</p>
<h3>5.4 意见反馈和投诉举报</h3>
<p>您可以按照我们公示的制度进行投诉或举报。如果您有任何意见或您认为您的个人信息权利可能受到侵害,或者发现侵害个人信息权利的线索,您可以通过Voitrans APP【设置】 - 【用户反馈】与我们联系。</p>
<h3>5.5 访问隐私政策</h3>
<p>您可以在Voitrans平台的注册页面,或者在Voitrans APP【设置】 -【个人中心】 - 【 隐私政策 】查看本隐私政策。</p>
<p>请您了解,本隐私政策中所述的 Voitrans及相关服务可能会根据您所使用的手机型号、系统版本、软件应用程序版本、移动客户端等因素而有所不同。最终的产品和服务以您所使用的Voitrans 软件及相关服务为准。</p>
<h2>6. 停止运营并向您告知</h2>
<p>如我们停止运营,我们将及时停止收集您个人信息的活动,将停止运营的通知以逐一送达或公告的形式通知您,并对所持有的您的个人信息进行删除或匿名化处理。</p>
<h3>6.1 未成年人通用条款</h3>
<p>a. 若您是已满14周岁但未满 18 周岁的未成年人,在使用Voitrans平台及相关服务前,应在您的父母或其他监护人监护、指导下共同阅读并同意本隐私政策。</p>
<p>b. 若您是未满 14 周岁的未成年人的监护人,在使用Voitrans 平台及相关服务前,应由您代被监护人阅读并同意本隐私政策。</p>
<p>c. 我们根据国家相关法律法规的规定保护未成年人的个人信息,只会在法律允许、父母或其他监护人明确同意或保护未成年人所必要的情况下收集、使用或披露未成年人的个人信息 ;
如果我们发现在未事先获得可证实的父母或其他监护人同意的情况下收集了未成年人的个人信息,则会设法尽快删除相关信息。同时我们建立了严格的儿童信息收集使用规则,以保护儿童个人信息安全。</p>
<p>d. 若您是未成年人的监护人,当您对您所监护的未成年人的个人信息有相关疑问时,请通过本隐私政策公示的联系方式与我们联系。</p>
<h2>7. 隐私政策的修订和通知</h2>
<h3>7.1 为了给您提供更好的服务,Voitrans
平台及相关服务将不时更新与变化,我们会适时对本隐私政策进行修订,这些修订构成本隐私政策的一部分并具有等同于本隐私政策的效力,未经您明确同意,我们不会削减您依据当前生效的本隐私政策所应享受的权利。</h3>
<h3>7.2 本隐私政策更新后,我们会在Voitrans 平台发出更新版本,并在更新后的条款生效前通过官方系统公告或其他适当的方式提醒您更新的内容,以便您及时了解本隐私政策的最新版本。</h3>
<h2>8. 联系我们</h2>
<h3>8.1 如果您对个人信息保护问题有投诉、建议、疑问,您可以通过Voitrans APP【设置】 - 【用户反馈】与我们联系,我们核查并验证您的用户身份后会及时给您反馈,一般情况下我们将在10个工作日内回复您的请求。</h3>
<h3>8.2 如对本隐私政策内容有任何疑问、意见或建议,您可以通过Voitrans APP【设置】 - 【用户反馈】与我们联系。</h3>
<h2>9. 第三方信息共享清单</h2>
<p>以下为我们接入的第三方SDK名称、开发者信息及其隐私政策链接说明,便于您更清楚地了解您的个人信息使用与保护情况:</p>
<h3>9.1 微信OpenSDK Android</h3>
<p>信息获取:设备号、IP地址、设备软件信息、设备识别码(IMEI、Android ID、IDFA、OAID、OPENUDID、GUID、ICCID、SIM 卡 IMSI
信息、IP、MAC地址)、设备识别符、所在地区、设备相关应用信息以及其他与服务相关的日志信息</p>
<p>使用目的:微信登录与分享,详情见SDK隐私政策</p>
<p>使用场景:在用户使用微信登录与分享时使用,详情见SDK隐私政策</p>
<p>合作方主体:深圳市腾讯计算机系统有限公司</p>
<p>收集方式:SDK自行采集</p>
<p>隐私政策链接:https://support.weixin.qq.com/cgi-bin/mmsupportacctnodeweb-bin/pages/RYiYJkLOrQwu0nb8</p>
<h3>9.2 导航SDK</h3>
<p>信息获取:应用名、应用版本号、设备品牌及型号、操作系统、运营商信息、屏幕分辨率、传感器信息(矢量、加速度、压力、方向、地磁 、陀螺、温度、光敏、nema信号)、设备信号强度信息</p>
<p>使用目的:使用高德地图进行导航</p>
<p>使用场景:使用高德地图进行导航</p>
<p>合作方主体:北京高德图强科技有限公司</p>
<p>收集方式:SDK自行采集</p>
<p>隐私政策链接:https://lbs.amap.com/pages/privacy/</p>
<h3>9.3 地图SDK</h3>
<p>信息获取:应用名、应用版本号、设备品牌及型号、操作系统、网络信息、设备信号强度信息等</p>
<p>使用目的:地图展示与交互</p>
<p>使用场景:地图相关功能</p>
<p>合作方主体:北京高德图强科技有限公司</p>
<p>收集方式:SDK自行采集</p>
<p>隐私政策链接:https://lbs.amap.com/pages/privacy/</p>
<h3>9.4 定位SDK</h3>
<p>信息获取:位置信息(GPS、Wi-Fi、基站)、设备信息、网络信息等</p>
<p>使用目的:提供定位服务</p>
<p>使用场景:位置相关功能</p>
<p>合作方主体:北京高德图强科技有限公司</p>
<p>收集方式:SDK自行采集</p>
<p>隐私政策链接:https://lbs.amap.com/pages/privacy/</p>
<h3>9.5 轻量版地图SDK</h3>
<p>信息获取:应用名、应用版本号、设备信息、网络信息等</p>
<p>使用目的:地图工具与渲染优化</p>
<p>使用场景:地图相关工具功能</p>
<p>合作方主体:北京高德图强科技有限公司</p>
<p>收集方式:SDK自行采集</p>
<p>隐私政策链接:https://lbs.amap.com/pages/privacy/</p>
<h3>9.6 APP支付客户端SDK</h3>
<p>信息获取:设备标识、设备信息、软件安装列表、网络信息等(详见官方隐私政策)</p>
<p>使用目的:支付宝账号登录与调起支付能力</p>
<p>使用场景:支付相关功能</p>
<p>合作方主体:支付宝(杭州)信息技术有限公司</p>
<p>收集方式:SDK自行采集</p>
<p>隐私政策链接:https://opendocs.alipay.com/open/54/01g6qm#%E6%94%AF%E4%BB%98%E5%AE%9D%20App%20%E6%94%AF%E4%BB%98%E5%AE%A2%E6%88%B7%E7%AB%AF%20SDK%20%E9%9A%90%E7%A7%81%E6%94%BF%E7%AD%96</p>
<h3>9.7 灯塔 SDK Android</h3>
<p>信息获取:SDK或API版本、应用标识符、应用版本、终端厂商、操作系统版本、语言、时区、网络状态、崩溃与使用日志、IP地址等(详见官方隐私政策)</p>
<p>使用目的:应用质量与数据上报服务</p>
<p>使用场景:稳定性监测与性能分析</p>
<p>合作方主体:深圳市腾讯计算机系统有限公司</p>
<p>收集方式:SDK自行采集</p>
<p>隐私政策链接:https://privacy.qq.com/document/preview/a19a8cf4f2354306b137a7db39d32024</p>
</body>
</html>

381
doc/ysxy_en.html

@ -0,0 +1,381 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Voitrans Privacy Policy</title>
<style>
body {
font-family: "Calibri", "Segoe UI", "Roboto", "Helvetica Neue", Arial, sans-serif;
line-height: 1.6;
color: #333;
margin: 0;
padding: 0;
background-color: #fff;
overflow-x: hidden;
word-wrap: break-word;
word-break: break-all;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px 40px;
}
h1 {
font-size: 24px;
font-weight: bold;
text-align: center;
margin-bottom: 24px;
color: #333;
}
h2 {
font-size: 20px;
font-weight: bold;
margin-top: 24px;
margin-bottom: 12px;
color: #333;
}
h3 {
font-size: 18px;
font-weight: bold;
margin-top: 20px;
margin-bottom: 10px;
color: #333;
}
h4 {
font-size: 16px;
font-weight: bold;
margin-top: 16px;
margin-bottom: 8px;
color: #555;
}
p {
margin-bottom: 12px;
text-align: justify;
font-size: 14px;
word-wrap: break-word;
word-break: break-all;
}
ul, ol {
margin-bottom: 12px;
padding-left: 20px;
}
li {
margin-bottom: 6px;
font-size: 14px;
word-wrap: break-word;
word-break: break-all;
}
.date-info {
font-size: 14px;
color: #666;
margin-bottom: 5px;
}
/* Responsive adjustments */
@media (max-width: 600px) {
.container {
padding: 15px;
}
h1 {
font-size: 22px;
}
h2 {
font-size: 18px;
}
h3 {
font-size: 16px;
}
}
</style>
</head>
<body>
<div class="container">
<h1>Voitrans Privacy Policy</h1>
<p class="date-info">Last Updated: May 27, 2025</p>
<p class="date-info">Effective Date: May 27, 2025</p>
<p>Welcome to use Voitrans Software and Services</p>
<p>1. Voitrans Provided by Saitong Industries Inc. (hereinafter referred to as "the Company"). Can help users achieve Bluetooth devices and other products management. We understand the importance of personal information to our users (hereinafter referred to as "you") and that effective protection of your personal information is the cornerstone of the healthy and sustainable development of our business. Thank you for your use and trust in Voitrans products or services! We are fully aware that this trust does not come easily, we adhere to the principle of openness and transparency, to express to you our rules for processing your personal information, we use legal and legitimate ways and clear and reasonable purposes to process your personal information. Special note: Please be sure to read and understand this Privacy Policy carefully before using our products or services so that you can make appropriate choices.</p>
<p>2. This Privacy Policy explains to you how we collect, use, store and share your personal information when you use Voitrans. Personal information refers to all kinds of information recorded by electronic or other means that can identify a specific natural person or reflect the activities of a specific natural person alone or in combination with other information. Voitrans respects and protects the personal privacy of all users of the service. Except as otherwise provided in this Privacy Policy, Voitrans will not disclose this information to the public or provide it to third parties without your prior permission.</p>
<p>3. When you use a third party's product or service through an App Marketplace product or service, your personal information shall be subject to the third party's privacy policy.</p>
<p>4. Voitrans This Privacy Policy will be updated from time to time. By agreeing to the Voitrans Service Usage Agreement and beginning to use Voitrans, you are deemed to have agreed to all of this Privacy Policy. If you do not agree to this Privacy Policy, please do not use Voitrans Software and Services.</p>
<p>5. In order to analyze and measure the effectiveness of relevant services, we will use and disclose your personal information in accordance with the provisions of this Privacy Policy.</p>
<h3>This Privacy policy will help you understand the following:</h3>
<ul>
<li>1 The information we collect</li>
<li>2 Storage of information</li>
<li>3 Information security</li>
<li>4 How do we use the information we collect</li>
<li>5 Information sharing</li>
<li>6 How do you manage your personal information</li>
<li>7 Application permission description</li>
<li>8 Access third-party SDKS</li>
<li>9 Protection of minors</li>
<li>10 Effective and updated Privacy Policy</li>
<li>11 How to contact us</li>
</ul>
<h3>1. The information we collect</h3>
<p>1. Use Voitrans at the beginning We will start collecting data about your usage of the application</p>
<p>2. Voitrans may obtain personal information about you from third parties or business partners through lawful means</p>
<p>3. In order to provide you with better products and services, give you network security during use, maintain the normal operation of products and optimize and improve, the purpose of our information services, after you actively click to agree to this privacy policy, use the information we provide. During the service, in addition to the personal information necessary to ensure the normal operation of the basic functions of the App in accordance with national laws and regulations, we will collect other personal information from you:</p>
<p>3.1 In order to identify risk users, judge the authenticity of users and prevent cheating in an all-round way, we will read your device information every time you open the software, including: (Device model, device MAC address, device unique identifier (IMEI, AndroidID, Device ID, MEID, UUID, GAID, OAID, IDFA, OpenUDID, GUID, IMSI, CCID, etc.) MEID, serial number, SSID and BSSID of WIFI), read Bluetooth address, operating system version, operating system name, user login account and password information;</p>
<p>3.2 When you use our products and services, we may collect certain information through network log information or certain programs and software, such information may include: details of the use of products and services, such as the opening time of your application, the length of use, and the address of the page visited; Device event information, such as crashes, system activity, etc., to optimize your device and improve our services;</p>
<p>3.3 To identify applications where equipment is at risk, provide more secure functional services. Therefore, we need to obtain your application/application installation list in the process to ensure the normal operation of the product and protect the security of the device.</p>
<p>3.4 In order to analyze the use of application functions by users and determine the authenticity of users, we need to conduct data statistics, and collect the above device information, including device MAC address and device unique identifier, when your device is in use.</p>
<p>3.5 Device signal: the network status of the device you use, WIFI access point information, etc.</p>
<p>3.6 Location Information: We may use GPS, WiFi or other technical means to collect and process information about your location for updating local information, providing content services, etc.</p>
<p>For more information, please click "Personal Information Collection List".</p>
<p>1. For the more sensitive personal information in the above information, such as user device information (IMEI number, call status and identification number), GPS location information, photo media content and file access rights, we will obtain your consent before collection. For some non-sensitive information, the collection may be default and automatic. You can restrict our collection of relevant information or use of certain permissions from your mobile device by adjusting the Settings option for your mobile device. When you restrict our access to a certain permission, we may not be able to continue to provide you with the corresponding services, and no longer process your corresponding information.</p>
<p>2. We will not collect your ID card number, personal biometric information, bank account number, property information, credit information, health and physiological information and other personal sensitive information.</p>
<p>3. About sensitive permissions: In order to properly use the application functions, the product needs to obtain the following permissions in order to provide functional services related to normal products.</p>
<h4>1 Obtain storage read and write permissions</h4>
<p>1 How to get: pop-up prompt, when the permission is obtained, the user will take the initiative to click agree application will use this permission</p>
<p>2 Purpose and scope of use: It is used to scan the resource cache files and thumbnails in the system, load music resources and product pictures. It is displayed on the App interface to facilitate users to view and operate</p>
<h4>2 Obtain permission to the application installation list</h4>
<p>1 How to get: pop-up prompt, when the permission is obtained, the user will take the initiative to click agree application will use this permission</p>
<p>2 Purpose and scope of use: When the application needs to use advertising promotion services, the third-party advertising platform, Youmon +SDK, needs to obtain the "app software installation list permission" of the device to prevent the user from pushing the application already owned by the user and improve the user experience.</p>
<h4>3 The permission to obtain device status information</h4>
<p>Includes: (Device model, device MAC address, device unique identifier (IMEI, AndroidID, Device ID, MEID, UUID, GAID, OAID, IDFA, OpenUDID, GUID, IMSI, CCID, etc.) MEID, serial number, SSID and BSSID of WIFI, read Bluetooth address), operating system version, operating system name, etc.;</p>
<p>1 How to get: pop-up prompt, when the permission is obtained, the user will take the initiative to click agree application will use this permission</p>
<p>2 Purpose and Scope of use: When using our application, in order to analyze the user's use of application functions and judge the user's authenticity, we will synchronize the permission to third-party SDKS, including Autonavi SDK, Youmon +SDK, etc.</p>
<h4>4 Access to location information</h4>
<p>1 How to obtain: pop-up prompts, when the permission is obtained, the user will use this permission only when he actively clicks agree with the application.</p>
<p>2 Purpose and Scope of use: When the application needs to use GPS, WiFi or other functions, the product needs to collect your location and information to search for Bluetooth devices in nearby locations.</p>
<p>Note: For more application permissions, see this document "Privacy Policy" Section 7 "Application Permission Description"</p>
<h3>2. Storage of information</h3>
<p>1. Where the information is stored</p>
<p>The personal information we collect and generate in the People's Republic of China will be stored on our servers and/or those of our affiliates.</p>
<p>2. Information storage and processing</p>
<p>We store your personal information only for the period necessary to achieve the purpose or as long as required by law and regulation. After you stop using this product, we will immediately stop collecting and processing your personal information and application data. When the above period is exceeded, we will delete or anonymize the personal information you have provided to us.</p>
<p>In addition to the necessary functions, Voitrans needs to apply for corresponding system permissions. The server side of the cloud does not store user personal information, and the third-party SDK accessed will be anonymized and de-identified by the service provider (Amu Statistics SDK, Autonavi SDK), so users cannot be tracked. Information stored on the user's phone will be automatically deleted when the user uninstalls Voitrans or clears the cache.</p>
<h3>3. Information security</h3>
<p>1. Voitrans stores and protects your personal information using industry-standard security measures and technologies, such as authentication, data encryption, restricted data center access and other security measures to ensure that your information is secure from disclosure, alteration and destruction. Despite the aforementioned security measures, please note that no security measure can be 100% secure.</p>
<p>2. When you use the services provided by Voitrans, please protect your personal information. If you find that your personal information has been compromised, please contact us immediately so that we can take appropriate measures.</p>
<h3>4. How do we use the information we collect</h3>
<p>1. When implementing application business functions, we may use your personal information to ensure the integrity and security of the products and services we provide to you;</p>
<p>2. We will understand your usage habits through the collected information, and with the help of data analysis, identify the acceptability of services, your usage habits, etc., in order to test and create new products, functions and services, improve the service level, and help us improve existing services and develop new services;</p>
<p>3. We may use your personal information for customer surveys about the products and services, for sending notices about the products and services, and for commercial promotion;</p>
<p>4. We may use your information for internal analysis and research related to the application;</p>
<h3>5. Information sharing</h3>
<p>At present, we will not actively share or transfer your personal information to third parties outside the company, if there is other sharing or transfer of your personal information, we will directly or confirm that the third party has obtained your express consent to the above behavior.</p>
<p>We will not publicly disclose the personal information we collect. If it is necessary to publicly disclose it, we will inform you of the purpose of the public disclosure, the type of information disclosed and the sensitive information that may be involved, and obtain your express consent.</p>
<p>As our business continues to develop, we may engage in mergers, acquisitions, asset transfers and other transactions, and we will inform you of the relevant circumstances, in accordance with laws and regulations and no less than the standards required by this Guide to continue to protect your personal information or require a new controller to continue to protect your personal information.</p>
<p>In addition, according to relevant laws and regulations and national standards, we may share, transfer and publicly disclose personal information without prior authorization and consent of the personal information subject under the following circumstances:</p>
<ul>
<li>1 Directly related to national security and national defense security;</li>
<li>2 Directly related to public safety, public health or major public interests;</li>
<li>3 Directly related to criminal investigation, prosecution, trial and execution of judgments;</li>
<li>4 In order to protect the life, property and other major legitimate rights and interests of the personal data subject or other individuals, but it is difficult to obtain the consent of the person;</li>
<li>5 Personal information disclosed to the public by the personal information subject;</li>
<li>6 Collecting personal information from legally publicly disclosed information, such as legitimate news reports, government information disclosure and other channels.</li>
</ul>
<h3>6. How do you manage your personal information</h3>
<p>In accordance with the relevant laws, regulations and standards of China, as well as the common practices of other countries and regions, we guarantee that you exercise the following rights to your personal information:</p>
<h4>1. Correct your personal information</h4>
<p>If you find that there is an error in your personal information processed by us, you have the right to correct or update the wrong or incomplete information. If you are unable to operate independently in the account center, you can email saitong.voitrans@gmail.com Contact us</p>
<h4>2. Delete your personal information</h4>
<p>In the following cases, you may make a request to us to delete your personal information:</p>
<ul>
<li>If we process personal information in violation of laws and regulations;</li>
<li>If we collect and use your personal information without your consent;</li>
<li>If our processing of personal information violates our agreement with you;</li>
<li>If you no longer use our products or services;</li>
<li>If we no longer provide you with products or services.</li>
</ul>
<p>Contact us. We will process your request within saitong.voitrans@gmail.com Contact us. We will send it to you after receiving it 30 working days of receipt</p>
<h4>3. Change the scope of your consent</h4>
<p>You can contact us by email saitong.voitrans@gmail.com Contact us. At your request, we will no longer collect, use or disclose your personal information. Please note that your withdrawal of consent or deletion of your personal information may affect your use of some of our services.</p>
<h4>4 Access and copy personal information</h4>
<p>You may, in accordance with the provisions of the relevant laws, provide your imei (phone serial number) or oaid Or Android ID After the account information and other information, you can apply to us for access to and copy your personal information, you can email to 3514406195@qq.com Get in touch with us.</p>
<h4>5. In response to your above request</h4>
<p>For security purposes, you may need to provide a written request or otherwise prove your identity. We may ask you to verify your identity before processing your request. For your reasonable request, we will respond and deal with it in a timely manner. We may reject requests that are unnecessarily repetitive, require too much technology (for example, the development of new systems or fundamental changes to existing practices), pose a risk to the legitimate interests of others, or are highly impractical.</p>
<p>In the following circumstances, according to the requirements of laws and regulations, we will not be able to respond to your request:</p>
<ul>
<li>Related to national security and national defense security;</li>
<li>In connection with criminal investigation, prosecution and trial;</li>
<li>There is sufficient evidence that you have subjective malice or abuse of rights;</li>
<li>Responding to your request will cause serious damage to the legitimate rights and interests of you or other individuals and organizations.</li>
</ul>
<h4>6. Account cancellation</h4>
<p>User can be in Perform [account cancellation] operation on the APP. Operation steps:</p>
<ol>
<li>Go to the [My] page</li>
<li>Click the [Settings] button on the upper right</li>
<li>Click [Cancel account] to confirm</li>
</ol>
<p>After you log out, the information about the user account is cleared</p>
<h3>7. Application permission description</h3>
<p>In order to provide better products and services, when you use the software, we will apply for the following rights, when you enter the home page or use the function will request authorization, if you refuse, some of the corresponding functions will not be able to use normally. The specific purposes and reminders of permissions are described in detail as follows:</p>
<h4>1 Location rights:</h4>
<p>android.permission.ACCESS_COARSE_LOCATION</p>
<p>android.permission.ACCESS_FINE_LOCATION</p>
<p>pass WiFi or mobile base station to obtain the user's latitude and longitude location information</p>
<p>When you use In Voitrans, we will search for your attached Bluetooth device based on your geographical location. At the same time, in order to provide more stable services, optimize products and improve experience, we will share the above information with three SDKS, such as Youmon and Autonavi, to obtain Voitrans operating data and functional services.</p>
<p>Reminder mode: A prompt indicating the permission to start the application for the first time is displayed, requiring the user to confirm acceptance. User Agreement and Privacy Policy description.</p>
<h4>2</h4>
<p>android.permission.READ_EXTERNAL_STORAGE</p>
<p>android.permission.WRITE_EXTERNAL_STORAGE</p>
<p>This permission is required when you access an application to perform application management functions.</p>
<p>Reminder method: User Agreement and Privacy Policy description.</p>
<h4>3 Network permissions:</h4>
<p>android.permission.INTERNET</p>
<p>When you use These permissions are required for Voitrans's information services and version upgrade services, and in order to improve the user experience and optimize the service capabilities, third-party SDKS such as Friends will also use these permissions.</p>
<p>Reminder mode: User Agreement and Privacy Policy description.</p>
<h4>4 Get network status permissions:</h4>
<p>android.permission.ACCESS_NETWORK_STATE</p>
<p>android.permission.ACCESS_WIFI_STATE</p>
<p>It is used to obtain whether the current network connection is valid, determine whether the current 4G environment is , and whether to remind the network environment changes, thus affecting the loading of information content. This permission is applied for when you use Voitrans.</p>
<p>Changes in the state of the network affect the uploading and loading of data. Therefore, the access to network status permission will be shared with friends + and other platforms.</p>
<p>Reminder method: User Agreement and Privacy Policy description.</p>
<h4>5 Get task list permissions:</h4>
<p>android.permission.GET_TASKS</p>
<p>This permission is used to obtain the application list for the software management function. When you use the software management function, you need to read the applications installed on the mobile phone.</p>
<p>Reminder mode: User Agreement and Privacy Policy description.</p>
<h4>6 Obtain MAC address permission</h4>
<p>android.permission.ACCESS_WIFI_STATE</p>
<p>android.permission.INTERNET</p>
<p>android.permission.ACCESS_NETWORK_STATE</p>
<p>When you use Voitrans, the application will need to obtain MAC address permissions:</p>
<p>When an application needs to report target conversion data, third-party platforms such as Youmon +SDK need to use MAC.</p>
<p>Reminder method: User Agreement and Privacy Policy description.</p>
<h4>7 Obtain permission to record audio</h4>
<p>android.permission.RECORD_AUDIO</p>
<p>When you use the voice input function of Voitrans, you need to use the permission to record audio, and mainly use the voice input for translation and other related functions.</p>
<p>Reminder method: User Agreement and Privacy Policy description , the user dynamically pops the box when required.</p>
<h4>8 Obtain SSID permission for WIFI</h4>
<p>When this permission is used, the app reads the SSID permission for WIFI:</p>
<p>Scope of use and purpose: When the application needs to use data analysis services, third-party platforms such as +SDK need to read the device's "WIFI SSID permission" to provide users with more accurate and effective functional services.</p>
<p>Reminder method: User Agreement and Privacy Policy description.</p>
<h4>9 Get Bluetooth access</h4>
<p>When this permission is used, the app reads the Bluetooth permission:</p>
<p>Scope of use and purpose: Bluetooth devices for searching and configuring accessories, such as Bluetooth headsets, Bluetooth watches, etc. Easy for users to manage</p>
<p>Reminder method: A prompt indicating the permission to start the application for the first time is displayed, requiring the user to confirm acceptance. User Agreement and Privacy Policy description.</p>
<h4>10 Get the BSSID permission for WiFi</h4>
<p>When the application needs to distinguish and identify the user to provide functional services and data statistics, it will read the "WiFi BSSID" permission of the device for:</p>
<p>Scope of use and purpose: 1 Third-party platforms: such as Youmeng SDK, Bugly SDK, Autonavi SDK</p>
<p>Reminder method: User Agreement and Privacy Policy description.</p>
<h4>11 Obtain the application installation permission</h4>
<p>android.permission.REQUEST_INSTALL_PACKAGES</p>
<p>The software will use the application installation permission, which is mainly used to allow users to install a new version and experience new functions when there is a new version.</p>
<p>Reminder mode: User Agreement and Privacy Policy description.</p>
<h4>12 Get permissions for the camera</h4>
<p>android.permission.CAMERA</p>
<p>Voitrans uses camera permissions to scan QR codes and bind Bluetooth devices such as Bluetooth headsets and watches.</p>
<p>Reminder method: A prompt indicating the permission to start the application for the first time is displayed, requiring the user to confirm acceptance. User Agreement and Privacy Policy description.</p>
<p><strong>Special note:</strong></p>
<p>1 Application integration within their Allies SDK, Scott map SDK in the user agrees to allow after use, application in the background/foreground for ICCID, IMSI, IMEI, SN, ANDROID, BSSID, ANDROID ID, SSID, IMSI and other personal information;</p>
<p>Remarks: More Please see the following SDK-related content and permissions [VIII. Access to third-party SDKS list]</p>
<h3>8. Access third-party SDKS</h3>
<p>1 In order to ensure the stable operation and functional realization of our client, so that you can use and enjoy more services and functions, our application will be embedded in the software tool development kit (SDK) or other similar applications of third parties, these third parties will collect and process relevant information in accordance with their own privacy policies, in order to normally provide functions and advertising services. You can learn about the information collection and processing rules of the third party in the following section. We will conduct strict security tests on the development kits (SDKS) for partners to obtain information, in order to protect the reasonable use and security of your personal information. Please note that third-party SDKS may change the data processing types due to their version upgrades. Please refer to the privacy policies published by third-party SDKS. See the details below or click to view the Third Party SDK List.</p>
<h4>8.1 WeChat OpenSDK Android (com.tencent.mm.opensdk)</h4>
<p>Information Obtained: Device number, IP address, device software information, device identification code (IMEI, Android ID, IDFA, OAID, OPENUDID, GUID, ICCID, SIM card IMSI information, IP, MAC address), device identifier, region, device-related application information, and other service-related log information</p>
<p>Purpose of Use: WeChat login and sharing</p>
<p>Developer: Shenzhen Tencent Computer Systems Company Limited</p>
<p>Collection Method: SDK self-collection</p>
<p>Privacy Policy Link: https://support.weixin.qq.com/cgi-bin/mmsupportacctnodeweb-bin/pages/RYiYJkLOrQwu0nb8</p>
<h4>8.2 Navigation SDK (com.amap.api.navi)</h4>
<p>Information Obtained: Application name, application version number, device brand and model, operating system, carrier information, screen resolution, sensor information (vector, acceleration, pressure, direction, geomagnetic, gyroscope, temperature, light sensor, NMEA signal), device signal strength information</p>
<p>Purpose of Use: Navigation using Amap</p>
<p>Developer: Beijing Gaode Tuqiang Technology Co., Ltd.</p>
<p>Collection Method: SDK self-collection</p>
<p>Privacy Policy Link: https://lbs.amap.com/pages/privacy/</p>
<h4>8.3 Map SDK (com.amap.api.maps)</h4>
<p>Information Obtained: Application name, application version, device brand and model, operating system, network information, device signal strength, etc.</p>
<p>Purpose of Use: Map display and interaction</p>
<p>Developer: Beijing Gaode Tuqiang Technology Co., Ltd.</p>
<p>Collection Method: SDK self-collection</p>
<p>Privacy Policy Link: https://lbs.amap.com/pages/privacy/</p>
<h4>8.4 Location SDK (com.amap.api.location)</h4>
<p>Information Obtained: Location information (GPS, Wi-Fi, base station), device information, network information, etc.</p>
<p>Purpose of Use: Provide location services</p>
<p>Developer: Beijing Gaode Tuqiang Technology Co., Ltd.</p>
<p>Collection Method: SDK self-collection</p>
<p>Privacy Policy Link: https://lbs.amap.com/pages/privacy/</p>
<h4>8.5 Lite Map SDK (com.amap.api.maps.utils)</h4>
<p>Information Obtained: Application name, application version, device information, network information, etc.</p>
<p>Purpose of Use: Map tools and rendering optimization</p>
<p>Developer: Beijing Gaode Tuqiang Technology Co., Ltd.</p>
<p>Collection Method: SDK self-collection</p>
<p>Privacy Policy Link: https://lbs.amap.com/pages/privacy/</p>
<h4>8.6 Alipay App Client SDK (com.alipay.sdk)</h4>
<p>Information Obtained: Device identifiers, basic device information, installed software list, and network information (see official privacy policy for details)</p>
<p>Purpose of Use: Alipay account login and payment invocation</p>
<p>Developer: Alipay (Hangzhou) Information Technology Co., Ltd.</p>
<p>Collection Method: SDK self-collection</p>
<p>Privacy Policy Link: https://opendocs.alipay.com/open/54/01g6qm#%E6%94%AF%E4%BB%98%E5%AE%9D%20App%20%E6%94%AF%E4%BB%98%E5%AE%A2%E6%88%B7%E7%AB%AF%20SDK%20%E9%9A%90%E7%A7%81%E6%94%BF%E7%AD%96</p>
<h4>8.7 Beacon SDK Android (com.tencent.beacon)</h4>
<p>Information Obtained: SDK/API version, platform, timestamp, app identifier, app version, device manufacturer, OS version, locale, timezone, network status (Wi-Fi, etc.), network logs, crash and usage data, IP address, etc. (see official privacy policy for details)</p>
<p>Purpose of Use: App quality monitoring and data reporting service</p>
<p>Developer: Shenzhen Tencent Computer Systems Company Limited</p>
<p>Collection Method: SDK self-collection</p>
<p>Privacy Policy Link: https://privacy.qq.com/document/preview/a19a8cf4f2354306b137a7db39d32024</p>
<h3>9. Protection of minors</h3>
<p>Users of our products and services may include Minors under the age of 18, minor users should seek the advice of their parents or guardians regarding this Privacy Policy before using our products, and use our services or provide your information to us after obtaining the consent of and under the guidance of their parents or guardians. Guardians of minors who have questions may contact us through the contact details in this Privacy Policy.</p>
<p>If you do not agree to the collection of the aforementioned information by the above third-party service providers, please stop using the Software immediately. During your use of the Software, these third parties will collect and process relevant information in accordance with their own privacy policies to provide some functions, advertising and other services. If the information is leaked due to the collection of the aforesaid information by the relevant third-party service provider, the relevant third-party service provider shall bear the corresponding legal responsibility.</p>
<h3>10. Effective and updated Privacy Policy</h3>
<p>1. This Privacy policy is effective from the date of publication.</p>
<p>2. As our business evolves and changes, our Privacy Policy may change. We reserve the right to change our privacy policy at any time, so please check back often. If we make changes to our Privacy Policy, we will post these updates on our website, apps, and where we deem appropriate to keep you informed. If the privacy policy is updated, it will take effect from the date of update. Your continued use of our products or services means that you agree to our changed Privacy Policy.</p>
<h3>11. How to contact us</h3>
<p>Saitong Industries Inc Established on November 22, 2024, registered address: 18305 E Valley Blvd, Unit C, City of Industry, CA 91744, USA. If you want to know more about our company and platform, you can contact us through the contact information provided in this policy (saitong.voitrans@gmail.com).</p>
</div>
</body>
</html>

9
ios/Runner/Info.plist

@ -54,6 +54,15 @@
<string>voitrans</string>
</array>
</dict>
<!-- PayPal 回跳的自定义 Scheme -->
<dict>
<key>CFBundleURLName</key>
<string>deepvoiceclient.payment</string>
<key>CFBundleURLSchemes</key>
<array>
<string>deepvoiceclient</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>

5
ios/Runner/RunnerProfile.entitlements

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
</plist>

11
lib/core/bindings/initial_binding.dart

@ -1,3 +1,4 @@
import '../../data/services/meeting/summary_task_service.dart';
import '/data/services/pay_service.dart';
import '/data/services/qq_music.dart';
@ -10,6 +11,8 @@ import '../../../data/services/ast_service.dart';
import '../../../data/services/speech_impl/azure_ast_service.dart';
import 'package:get/get.dart';
import '../../data/services/meeting/meeting_task_service.dart';
import '../../data/services/meeting/meeting_task_service2.dart';
import '../../data/services/meeting/meeting_task_aggregator.dart';
import '../../data/services/meeting/meeting_upload_service.dart';
import '../../data/services/novice_guide_service.dart';
import '../../data/services/speech_factory.dart';
@ -69,6 +72,14 @@ class InitialBinding extends Bindings {
// 会议助手任务服务
Get.lazyPut<MeetingTaskService>(() => MeetingTaskService(), fenix: true);
// 会议助手任务服务(极速识别版,2小时内音频)
Get.lazyPut<MeetingTaskService2>(() => MeetingTaskService2(), fenix: true);
// 会议助手任务服务聚合器(统一列表与状态)
Get.lazyPut<MeetingTaskAggregator>(() => MeetingTaskAggregator(),
fenix: true);
// 会议助手总结任务服务
Get.lazyPut<SummaryTaskService>(() => SummaryTaskService(), fenix: true);
// 会议助手音频上传
Get.lazyPut<MeetingUploadService>(() => MeetingUploadService(),

136
lib/core/translations/language/ar_sa.dart

@ -134,7 +134,8 @@ const Map<String, String> arSA = {
"initializing": "جاري التهيئة...",
"bluetoothInitializationFailure": "فشل تهيئة خدمة البلوتوث",
"checkingPermissions": "جاري التحقق من الأذونات...",
"lackPermissions": "أذونات البلوتوث مفقودة",
"lackPermissions":
"يرجى включить أذونات البلوتوث y الإمكانية الوصول إلى الموقع للبحث عن الأجهزة المحاورة",
"searchingDevice": "جاري البحث عن الجهاز...",
"findConnectedDevice": "تم العثور على جهاز متصل",
"notFound": "لم يتم العثور على أجهزة بلوتوث متصلة",
@ -179,21 +180,9 @@ const Map<String, String> arSA = {
"conferenceAssistant": "مساعد اجتماعات الأعمال",
"conferenceAssistantInfo":
"تسجيل محاضر الاجتماعات في الوقت الفعلي، ترجمة متعددة اللغات",
"studyAssistant": "مساعد تعلم اللغة",
"studyAssistantInfo": "تصحيح النطق، ممارسة المحادثة في الوقت الفعلي",
"travelTranslator": "مساعد ترجمة السفر",
"travelTranslatorInfo": "ترجمة صوتية فورية، مقدمة عن مناطق الجذب السياحي",
"beSearching": "جاري البحث:",
"noAssistantFound": "لم يتم العثور على مساعد الذكاء الاصطناعي المقابل",
"usageStats": "إحصائيات الاستخدام", // 用量统计
"usageStatsInfo": "عرض إحصائيات استخدامك", // 查看您的使用统计数据
"scene": "مشهد",
"youHaveSelected": "لقد اخترت:",
"newFunction": "وظيفة جديدة",
"youChoseTry": "لقد اخترت التجربة",
"aiSinger": "وضع مغني الذكاء الاصطناعي",
"aiSingerInfo":
"غنِ أي أغنية بصوت فنانك المفضل، حتى الأغاني التي كتبتها بنفسك",
"popularFunction": "مشاهد الوظائف الشائعة",
"tryNow": "جرب الآن",
// 商务会议助手页
"startMeeting": "بدء الاجتماع",
@ -428,8 +417,12 @@ const Map<String, String> arSA = {
'inputAttendees': 'أدخل الحضور',
// 设置页
"systemSettings": "إعدادات النظام",
"premiumMember": "عضو مميز",
"systemSettings": "إعدادات النظام", //系统设置
"vipRecharge": "إعادة صيغ العضوية", //会员充值
"aiRecharge": "عضو مميز", //AI充值
"translationRecharge": "إعادة صيغ الترجمة", //翻译充值
"meetingAssistantRecharge": "إعادة صيغ الاجتماع", //会议助手充值
"cloudSync": "إعادة صيغ مزامنة السحابة", //云端同步
"joinDevice": "الجهاز المتصل:",
"accountId": "معرف الحساب:",
"systemSetting": "إعدادات النظام",
@ -505,7 +498,7 @@ const Map<String, String> arSA = {
//Agent 模块
// agent View
"XiaoYan": "شياو يان",
"Lily": "Lily",
"clearChatHistory": "مسح سجل الدردشة",
"online": "متصل",
"inputMessage": "أدخل رسالة...",
@ -1159,4 +1152,111 @@ const Map<String, String> arSA = {
"justNow": "الآن",
"minutesAgo": "منذ @minutes دقيقة",
"yesterday": "أمس",
// Guide overlay keys (placeholders in English)
"sayLilyHint": "Say \"Lily Lily\" to the mic",
"imHere": "I’m here~",
"guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Lily”.",
"aiReplyCompleted": "Lily has finished the reply!",
"aiThinking": "Lily is thinking…",
"guideAwakenSuccess": "Great! Lily is awake—ask it to help.",
"confirmInput": "Confirm Input",
"guideClickSendPrefix": "Tap send, ",
"guideWeatherStart": "Tell Lily: “What’s the weather today?”",
"guideWeatherInput": "What’s the weather today?",
"guideWeatherSend": "Lily will report the weather in real time",
"guideWeatherEnd": "Lily can report weather live—try other commands",
"guideMusicStart": "Tell Lily: “Play some rock music”",
"guideMusicInput": "Play some rock music",
"guideMusicSend": "Lily will find music for you",
"guideMusicEnd": "Lily found music—try other commands",
"guideNavStart": "Tell Lily: “Navigate to Shenzhen Airport”",
"guideNavInput": "Navigate to Shenzhen Airport",
"guideNavSend": "Lily will plan the route",
"guideNavEnd": "Navigation set—try other commands",
"guideMeetingStart":
"Tell Lily: “Create a meeting reminder for 3pm tomorrow”",
"guideMeetingInput": "Create a meeting reminder for 3pm tomorrow",
"guideMeetingSend": "Lily will create a meeting reminder",
"guideMeetingEnd": "Reminder created—try other commands",
"guidePhoneStart": "Tell Lily: “Call Mom”",
"guidePhoneInput": "Call Mom",
"guidePhoneSend": "Lily will make the call",
"guidePhoneEnd": "Call placed—try other commands",
"guideSmsStart": "Tell Lily: “Send Dad a text: I’ll be home for dinner”",
"guideSmsInput": "Text Dad: I’ll be home for dinner",
"guideSmsSend": "Lily will send the message",
"guideSmsEnd": "Message sent—voice control is convenient",
// Goods pages common footer (placeholders)
'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans',
'copyrightVoitrans': '© 2025 Voitrans Technologies',
// Meeting goods page (placeholders)
'meetingHeaderDesc1':
'Audio recording, transcription, keyword search, and auto summary.',
'meetingHeaderDesc2':
'Suitable for business meetings, class notes, and interview minutes.',
'meetingAutoRecording': 'Auto recording and segmentation',
'meetingSpeakerTagging': 'Speaker labeling',
'meetingLongAudioTranscription': 'Long audio transcription',
'meetingKeyPointSummary': 'Key point extraction',
'meetingTopicNameSearch': 'Search by topic/name',
'meetingTimelineJump': 'Timeline jump',
'meetingExportSummary': 'Export minutes',
'meetingMultiPlatformShare': 'Share across platforms',
'meetingDisclaimer':
'Use in quiet environments; performance depends on microphone and network.',
// Translation goods page (placeholders)
'transHeaderDesc1':
'ترجمة متزامنة فورية وترجمة نصية مع بث صوتي منخفض التأخير.',
'transHeaderDesc2': 'مناسب للسفر والأعمال والخطب والتدريس.',
'translateZhEn': 'ترجمة صينية-إنجليزية',
'lowLatencyVoiceBroadcast': 'بث صوتي منخفض التأخير',
'multiLangTextTranslation': 'ترجمة نصية متعددة اللغات',
'termOptimizationContextPreserve': 'تحسين المصطلحات والحفاظ على السياق',
'lexiconTourBusinessLife': 'قواميس السفر/الأعمال/الحياة',
'personalVocabularyMemory': 'ذاكرة المفردات الشخصية',
'conversationSubtitleLargeText': 'عناوين المحادثة / وضع النص الكبير',
'colorHighContrast': 'تباين ألوان عالٍ',
'transDisclaimer':
'تعتمد جودة الترجمة على الميكروفون وزمن الشبكة والضوضاء المحيطة.',
// VIP goods page (placeholders)
'benefitsOverview': 'نظرة عامة على المزايا',
'higherQuota': 'حصة استخدام أعلى',
'lowerUnitPrice': 'سعر أقل لكل وحدة',
'priorityService': 'خدمة ذات أولوية',
'exclusiveSupportChannel': 'قناة دعم مخصصة',
'fastResponse': 'استجابة سريعة للمشكلات',
'eventsAndDiscounts': 'فعاليات وخصومات',
'memberExclusiveEvents': 'فعاليات حصرية للأعضاء',
'longTermDiscountPlan': 'خطة خصم طويلة الأجل',
'generalPrivileges': 'امتيازات عامة',
'earlyAccessNewFeatures': 'وصول مبكر إلى الميزات الجديدة',
'crossDeviceSync': 'مزامنة عبر الأجهزة',
'vipDisclaimer':
'تعتمد الفوائد الفعلية على تفاصيل الباقة وقد تتغير مع الإصدارات.',
// Goods names by id
'ai_001_name': 'الذكاء الاصطناعي الأساسي 100',
'ai_002_name': 'الذكاء الاصطناعي الأساسي 500',
'ai_003_name': 'الذكاء الاصطناعي الأساسي 1000',
'meet_001_name': 'اجتماع أساسي 100',
'meet_002_name': 'اجتماع أساسي 500',
'meet_003_name': 'اجتماع أساسي 1000',
'trans_001_name': 'ترجمة أساسية 100',
'trans_002_name': 'ترجمة أساسية 500',
'trans_003_name': 'ترجمة أساسية 1000',
// Goods descriptions by id
'ai_001_desc':
'يشمل 100 استخدام. الوصول إلى ميزات الذكاء الاصطناعي الأساسية.',
'ai_002_desc':
'يشمل 500 استخدام. الوصول إلى ميزات الذكاء الاصطناعي الأساسية.',
'ai_003_desc':
'يشمل 1000 استخدام. الوصول إلى ميزات الذكاء الاصطناعي الأساسية.',
'meet_001_desc': 'يشمل 100 تسجيل/نسخ لاجتماعات.',
'meet_002_desc': 'يشمل 500 تسجيل/نسخ لاجتماعات.',
'meet_003_desc': 'يشمل 1000 تسجيل/نسخ لاجتماعات.',
'trans_001_desc': 'يشمل 100 ترجمة (صوت/نص).',
'trans_002_desc': 'يشمل 500 ترجمة (صوت/نص).',
'trans_003_desc': 'يشمل 1000 ترجمة (صوت/نص).',
};

34
lib/core/translations/language/bg_bg.dart

@ -136,7 +136,8 @@ const Map<String, String> bgBG = {
"bluetoothInitializationFailure":
"Неуспешна инициализация на Bluetooth услугата",
"checkingPermissions": "Проверка на разрешенията...",
"lackPermissions": "Липсват Bluetooth разрешения",
"lackPermissions":
"Включете разрешенията за Bluetooth и достъп до локацията, за да се открият и свържат близки устройства",
"searchingDevice": "Търсене на устройства...",
"findConnectedDevice": "Намерено свързано устройство",
"notFound": "Не са намерени свързани Bluetooth устройства",
@ -182,22 +183,9 @@ const Map<String, String> bgBG = {
"conferenceAssistant": "Асистент за бизнес срещи",
"conferenceAssistantInfo":
"Записване на протоколи в реално време и многоезичен превод",
"studyAssistant": "Асистент за изучаване на езици",
"studyAssistantInfo": "Корекция на произношението и практика на говоренето",
"travelTranslator": "Пътуващ преводач",
"travelTranslatorInfo":
"Гласов превод в реално време и гид за забележителности",
"beSearching": "Търсене:",
"noAssistantFound": "Не е намерен съответстващ AI асистент",
"usageStats": "Статистика за използване",
"usageStatsInfo": "Прегледвайте статистика за използване на приложението",
"scene": "Сценарии",
"youHaveSelected": "Избрахте:",
"newFunction": "Нови функции",
"youChoseTry": "Избрахте да опитате",
"aiSinger": "AI певец режим",
"aiSingerInfo":
"Пейте всяка песен с гласа на любимия си изпълнител, дори собствените си творения",
"popularFunction": "Популярни функции",
"tryNow": "Опитай сега",
// 商务会议助手页
"startMeeting": "Започни среща",
@ -213,8 +201,12 @@ const Map<String, String> bgBG = {
'meetingTranscript': 'Протокол от срещата',
// 设置页
"systemSettings": "Системни настройки",
"premiumMember": "Премиум член",
"systemSettings": "Системни настройки", //系统设置
"vipRecharge": "Преплащане за VIP член", //会员充值
"aiRecharge": "Премиум член", //AI充值
"translationRecharge": "Преплащане за превод", //翻译充值
"meetingAssistantRecharge": "Преплащане за Сообщението", //会议助手充值
"cloudSync": "Преплащане за синхронизация в облака", //云端同步
"joinDevice": "Свързано устройство:",
"accountId": "ID на акаунта:",
"systemSetting": "Системни настройки",
@ -286,7 +278,7 @@ const Map<String, String> bgBG = {
//Agent 模块
// agent View
"XiaoYan": "Сяо Ян",
"Lily": "Lily",
"clearChatHistory": "Изчисти историята на чата",
"online": "Онлайн",
"inputMessage": "Въведете съобщение...",
@ -716,7 +708,7 @@ const Map<String, String> bgBG = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Сдвояване на устройства",
"connectYourDeepSoundHeadset": "Свържете вашите DeepSound слушалки",
"connectYourDeepSoundHeadset": "Свържете вашите Voitrans слушалки",
"bind": "Свържи",
"authorizeBind": "Разреши свързването",
"enterCode": "Моля въведете кода",
@ -779,7 +771,7 @@ const Map<String, String> bgBG = {
'pleaseGrantNecessaryPermissions':
'Моля предоставете необходимите разрешения',
'checkFailedRetry': 'Неуспешна проверка, моля опитайте отново',
'pleaseConnectDeepSoundDevice': 'Моля свържете DeepSound устройство',
'pleaseConnectDeepSoundDevice': 'Моля свържете Voitrans устройство',
'verificationFailedRetry': 'Неуспешна проверка, моля опитайте отново',
'invalidDeviceAddress': 'Невалиден адрес на устройството',
'bleDeviceAssociationFailed': 'Неуспешна асоциация с BLE устройството',

35
lib/core/translations/language/cs_cz.dart

@ -136,7 +136,8 @@ const Map<String, String> csCZ = {
"initializing": "Inicializace...",
"bluetoothInitializationFailure": "Inicializace služby Bluetooth selhala",
"checkingPermissions": "Kontrola oprávnění...",
"lackPermissions": "Chybí oprávnění Bluetooth",
"lackPermissions":
"Chybí oprávnění Bluetooth a přístup k lokaci, pro nalezení a připojení zařízení",
"searchingDevice": "Hledání zařízení...",
"findConnectedDevice": "Nalezeno připojené zařízení",
"notFound": "Nenalezena žádná připojená Bluetooth zařízení",
@ -181,21 +182,9 @@ const Map<String, String> csCZ = {
"conferenceAssistant": "Asistent obchodních schůzek",
"conferenceAssistantInfo":
"Záznam zápisů v reálném čase a vícejazyčný překlad",
"studyAssistant": "Asistent pro výuku jazyků",
"studyAssistantInfo": "Korekce výslovnosti a procvičování mluvení",
"travelTranslator": "Cestovní překladač",
"travelTranslatorInfo": "Hlasový překlad v reálném čase a průvodce památkami",
"beSearching": "Hledání:",
"noAssistantFound": "Nebyl nalezen odpovídající AI asistent",
"usageStats": "Statistika použití",
"usageStatsInfo": "Zobrazit statistiku použití aplikace",
"scene": "Scénáře",
"youHaveSelected": "Vybrali jste:",
"newFunction": "Nové funkce",
"youChoseTry": "Rozhodli jste se vyzkoušet",
"aiSinger": "AI zpěvák režim",
"aiSingerInfo":
"Zpívejte jakoukoliv píseň hlasem vašeho oblíbeného umělce, dokonce i vaše vlastní tvorbu",
"popularFunction": "Populární funkce",
"tryNow": "Vyzkoušet nyní",
// 商务会议助手页
"startMeeting": "Začít schůzku",
@ -211,8 +200,12 @@ const Map<String, String> csCZ = {
'meetingTranscript': 'Přepis schůzky',
// 设置页
"systemSettings": "Systémová nastavení",
"premiumMember": "Prémiový člen",
"systemSettings": "Systémová nastavení", //系统设置
"vipRecharge": "Přepayka VIP členství", //会员充值
"aiRecharge": "Prémiový člen", //AI充值
"translationRecharge": "Přepayka překladu", //翻译充值
"meetingAssistantRecharge": "Přepayka asistenta schůzky", //会议助手充值
"cloudSync": "Přepayka synchronizace v cloudu", //云端同步
"joinDevice": "Připojené zařízení:",
"accountId": "ID účtu:",
"systemSetting": "Systémová nastavení",
@ -283,7 +276,7 @@ const Map<String, String> csCZ = {
//Agent 模块
// agent View
"XiaoYan": "Xiao Yan",
"Lily": "Lily",
"clearChatHistory": "Vymazat historii chatu",
"online": "Online",
"inputMessage": "Zadejte zprávu...",
@ -310,7 +303,7 @@ const Map<String, String> csCZ = {
"swipeUpForMore": "Potáhněte nahoru pro více",
// Agent controller
'welcomeMessage': 'Ahoj! Jsem **Xiao Yan**, mohu vám pomoci s:\n\n'
'welcomeMessage': 'Ahoj! Jsem **Lily**, mohu vám pomoci s:\n\n'
'• Odpovídáním na otázky a poskytováním informací\n\n'
'• Překladem řeči v reálném čase\n\n'
'• Doporučováním hudby a podcastů\n\n'
@ -705,7 +698,7 @@ const Map<String, String> csCZ = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Párování zařízení",
"connectYourDeepSoundHeadset": "Připojte svá sluchátka DeepSound",
"connectYourDeepSoundHeadset": "Připojte svá sluchátka Voitrans",
"bind": "Svázat",
"authorizeBind": "Autorizovat svázání",
"enterCode": "Zadejte prosím kód",
@ -766,7 +759,7 @@ const Map<String, String> csCZ = {
'retryAuthorization': 'Zkusit autorizaci znovu',
'pleaseGrantNecessaryPermissions': 'Udělte prosím potřebná oprávnění',
'checkFailedRetry': 'Kontrola selhala, zkuste to prosím znovu',
'pleaseConnectDeepSoundDevice': 'Připojte prosím zařízení DeepSound',
'pleaseConnectDeepSoundDevice': 'Připojte prosím zařízení Voitrans',
'verificationFailedRetry': 'Ověření selhalo, zkuste to prosím znovu',
'invalidDeviceAddress': 'Neplatná adresa zařízení',
'bleDeviceAssociationFailed': 'Přidružení BLE zařízení selhalo',

36
lib/core/translations/language/da_dk.dart

@ -136,7 +136,8 @@ const Map<String, String> daDK = {
"bluetoothInitializationFailure":
"Bluetooth service initialisering mislykkedes",
"checkingPermissions": "Kontrollerer tilladelser...",
"lackPermissions": "Mangler Bluetooth tilladelser",
"lackPermissions":
"Mangler Bluetooth tilladelser og tilladelse til at tilgå lokationen",
"searchingDevice": "Søger efter enheder...",
"findConnectedDevice": "Fandt tilsluttet enhed",
"notFound": "Ingen tilsluttede Bluetooth enheder fundet",
@ -181,22 +182,9 @@ const Map<String, String> daDK = {
"conferenceAssistant": "Forretningsmøde assistent",
"conferenceAssistantInfo":
"Realtidsoptagelse af mødereferater og flersproget oversættelse",
"studyAssistant": "Sprogindlærings assistent",
"studyAssistantInfo": "Udtalerettelse og taleøvelse",
"travelTranslator": "Rejseoversætter",
"travelTranslatorInfo":
"Realtids stemmeoversættelse og turistattraktionsguide",
"beSearching": "Søger:",
"noAssistantFound": "Ingen tilsvarende AI assistent fundet",
"usageStats": "Brugsstatistik",
"usageStatsInfo": "Se statistik for brug af appen",
"scene": "Scenarier",
"youHaveSelected": "Du har valgt:",
"newFunction": "Nye funktioner",
"youChoseTry": "Du valgte at prøve",
"aiSinger": "AI sanger tilstand",
"aiSingerInfo":
"Syng enhver sang med din yndlingskunstners stemme, endda dine egne kreationer",
"popularFunction": "Populære funktioner",
"tryNow": "Prøv nu",
// 商务会议助手页
"startMeeting": "Start møde",
@ -212,8 +200,12 @@ const Map<String, String> daDK = {
'meetingTranscript': 'Mødeudskrift',
// 设置页
"systemSettings": "Systemindstillinger",
"premiumMember": "Premium medlem",
"systemSettings": "Systemindstillinger", //系统设置
"vipRecharge": "Opladning af VIP medlem", //会员充值
"aiRecharge": "Premium medlem", //AI充值
"translationRecharge": "Opladning af oversetning", //翻译充值
"meetingAssistantRecharge": "Opladning af mødeassistent", //会议助手充值
"cloudSync": "Opladning af cloud-synkronisering", //云端同步
"joinDevice": "Tilsluttet enhed:",
"accountId": "Konto-ID:",
"systemSetting": "Systemindstillinger",
@ -285,7 +277,7 @@ const Map<String, String> daDK = {
//Agent 模块
// agent View
"XiaoYan": "Xiao Yan",
"Lily": "Lily",
"clearChatHistory": "Ryd chathistorik",
"online": "Online",
"inputMessage": "Indtast besked...",
@ -312,7 +304,7 @@ const Map<String, String> daDK = {
"swipeUpForMore": "Stryg op for mere",
// Agent controller
'welcomeMessage': 'Hej! Jeg er **Xiao Yan**, jeg kan hjælpe dig med:\n\n'
'welcomeMessage': 'Hej! Jeg er **Lily**, jeg kan hjælpe dig med:\n\n'
'• Besvare spørgsmål og give information\n\n'
'• Realtids stemmeoversættelse\n\n'
'• Anbefale musik og podcasts\n\n'
@ -706,7 +698,7 @@ const Map<String, String> daDK = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Enhedsparring",
"connectYourDeepSoundHeadset": "Tilslut dine DeepSound øretelefoner",
"connectYourDeepSoundHeadset": "Tilslut dine Voitrans øretelefoner",
"bind": "Bind",
"authorizeBind": "Autoriser binding",
"enterCode": "Indtast venligst kode",
@ -767,7 +759,7 @@ const Map<String, String> daDK = {
'retryAuthorization': 'Prøv autorisation igen',
'pleaseGrantNecessaryPermissions': 'Giv venligst de nødvendige tilladelser',
'checkFailedRetry': 'Kontrol mislykkedes, prøv venligst igen',
'pleaseConnectDeepSoundDevice': 'Tilslut venligst DeepSound enhed',
'pleaseConnectDeepSoundDevice': 'Tilslut venligst Voitrans enhed',
'verificationFailedRetry': 'Verificering mislykkedes, prøv venligst igen',
'invalidDeviceAddress': 'Ugyldig enhedsadresse',
'bleDeviceAssociationFailed': 'BLE enhedsassociation mislykkedes',

134
lib/core/translations/language/de_de.dart

@ -139,7 +139,8 @@ const Map<String, String> deDE = {
"bluetoothInitializationFailure":
"Bluetooth-Dienst-Initialisierung fehlgeschlagen",
"checkingPermissions": "Berechtigungen werden überprüft...",
"lackPermissions": "Bluetooth-Berechtigungen erforderlich",
"lackPermissions":
"Bluetooth-Berechtigungen erforderlich und Zugriff auf die Lage erforderlich",
"searchingDevice": "Geräte werden gesucht...",
"findConnectedDevice": "Verbundenes Gerät gefunden",
"notFound": "Keine verbundenen Bluetooth-Geräte gefunden",
@ -185,22 +186,10 @@ const Map<String, String> deDE = {
"conferenceAssistant": "Geschäftstreffen-Assistent",
"conferenceAssistantInfo":
"Echtzeit-Protokollaufzeichnung und mehrsprachige Übersetzung",
"studyAssistant": "Sprachlern-Assistent",
"studyAssistantInfo": "Aussprachekorrektur und Sprechpraxis",
"travelTranslator": "Reise-Übersetzer",
"travelTranslatorInfo":
"Echtzeit-Sprachübersetzung und Sehenswürdigkeiten-Führung",
"beSearching": "Suche nach:",
"noAssistantFound": "Kein entsprechender KI-Assistent gefunden",
"usageStats": "Benutzungsstatistik",
"usageStatsInfo":
"Sehen Sie sich die Statistiken für die Benutzung der App an",
"scene": "Szenarien",
"youHaveSelected": "Sie haben ausgewählt:",
"newFunction": "Neue Funktionen",
"youChoseTry": "Sie haben sich entschieden zu versuchen",
"aiSinger": "KI-Sänger-Modus",
"aiSingerInfo":
"Singen Sie jedes Lied in der Stimme Ihres Lieblingskünstlers, sogar Ihre eigenen Kreationen",
"popularFunction": "Beliebte Funktionen",
"tryNow": "Jetzt versuchen",
// 商务会议助手页
"startMeeting": "Meeting starten",
@ -216,8 +205,12 @@ const Map<String, String> deDE = {
'meetingTranscript': 'Meeting-Transkript',
// 设置页
"systemSettings": "Systemeinstellungen",
"premiumMember": "Premium-Mitgliedschaft",
"systemSettings": "Systemeinstellungen", //系统设置
"vipRecharge": "VIP-Mitgliedschaft-Recharge", //会员充值
"aiRecharge": "Premium-Mitgliedschaft", //AI充值
"translationRecharge": "Übersetzungs-Recharge", //翻译充值
"meetingAssistantRecharge": "Meeting-Assistent-Recharge", //会议助手充值
"cloudSync": "Cloud-Synchronisierung-Recharge", //云端同步
"joinDevice": "Verbundenes Gerät:",
"accountId": "Konto-ID:",
"systemSetting": "Systemeinstellungen",
@ -288,7 +281,7 @@ const Map<String, String> deDE = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Chat-Verlauf löschen",
"online": "Online",
"inputMessage": "Nachricht eingeben...",
@ -315,7 +308,7 @@ const Map<String, String> deDE = {
"swipeUpForMore": "Nach oben wischen für mehr",
// Agent controller
'welcomeMessage': 'Hallo! Ich bin **XiaoYan**, ich kann Ihnen helfen:\n\n'
'welcomeMessage': 'Hallo! Ich bin **Lily**, ich kann Ihnen helfen:\n\n'
'• Fragen beantworten und Informationen bereitstellen\n\n'
'• Echtzeit-Sprachübersetzung\n\n'
'• Musik und Podcasts empfehlen\n\n'
@ -719,7 +712,7 @@ const Map<String, String> deDE = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Gerätekopplung",
"connectYourDeepSoundHeadset": "Verbinden Sie Ihr DeepSound-Headset",
"connectYourDeepSoundHeadset": "Verbinden Sie Ihr Voitrans-Headset",
"bind": "Binden",
"authorizeBind": "Bindung autorisieren",
"enterCode": "Bitte geben Sie den Code ein",
@ -737,7 +730,7 @@ const Map<String, String> deDE = {
"readyToPair": "Bereit zum Koppeln",
"preparingPairingEnvironment": "Kopplungsumgebung wird vorbereitet...",
"connectDeepSoundViaSystemBluetooth":
"Bitte verbinden Sie zuerst das DeepSound-Gerät über System-Bluetooth",
"Bitte verbinden Sie zuerst das Voitrans-Gerät über System-Bluetooth",
"deviceBindingConfirm": "Gerätebindungsbestätigung...",
"establishingDeviceAssociation": "Gerätezuordnung wird hergestellt...",
"waitingCompletePairing": "Bitte warten, Kopplung wird abgeschlossen...",
@ -746,7 +739,7 @@ const Map<String, String> deDE = {
// 配对错误状态文本
"ensureConnectedDeepSoundDevice":
"Bitte stellen Sie sicher, dass das verbundene Gerät DeepSound ist",
"Bitte stellen Sie sicher, dass das verbundene Gerät Voitrans ist",
"deviceAlreadyBoundToOtherAccount":
"Dieses Gerät ist bereits an ein anderes Konto gebunden",
"deviceAssociationFailed":
@ -783,7 +776,7 @@ const Map<String, String> deDE = {
'Bitte erteilen Sie die erforderlichen Berechtigungen',
'checkFailedRetry':
'Überprüfung fehlgeschlagen, bitte versuchen Sie es erneut',
'pleaseConnectDeepSoundDevice': 'Bitte verbinden Sie das DeepSound-Gerät',
'pleaseConnectDeepSoundDevice': 'Bitte verbinden Sie das Voitrans-Gerät',
'verificationFailedRetry':
'Verifizierung fehlgeschlagen, bitte versuchen Sie es erneut',
'invalidDeviceAddress': 'Ungültige Geräteadresse',
@ -880,4 +873,97 @@ const Map<String, String> deDE = {
"乌尔都语": "Urdu",
"波斯语": "Persisch",
"斯瓦希里语": "Swahili",
// Guide overlay keys (placeholders in English)
"sayLilyHint": "Say \"Lily Lily\" to the mic",
"imHere": "I’m here~",
"guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Lily”.",
"aiReplyCompleted": "Lily has finished the reply!",
"aiThinking": "Lily is thinking…",
"guideAwakenSuccess": "Great! Lily is awake—ask it to help.",
"confirmInput": "Confirm Input",
"guideClickSendPrefix": "Tap send, ",
"guideWeatherStart": "Tell Lily: “What’s the weather today?”",
"guideWeatherInput": "What’s the weather today?",
"guideWeatherSend": "Lily will report the weather in real time",
"guideWeatherEnd": "Lily can report weather live—try other commands",
"guideMusicStart": "Tell Lily: “Play some rock music”",
"guideMusicInput": "Play some rock music",
"guideMusicSend": "Lily will find music for you",
"guideMusicEnd": "Lily found music—try other commands",
"guideNavStart": "Tell Lily: “Navigate to Shenzhen Airport”",
"guideNavInput": "Navigate to Shenzhen Airport",
"guideNavSend": "Lily will plan the route",
"guideNavEnd": "Navigation set—try other commands",
"guideMeetingStart":
"Tell Lily: “Create a meeting reminder for 3pm tomorrow”",
"guideMeetingInput": "Create a meeting reminder for 3pm tomorrow",
"guideMeetingSend": "Lily will create a meeting reminder",
"guideMeetingEnd": "Reminder created—try other commands",
"guidePhoneStart": "Tell Lily: “Call Mom”",
"guidePhoneInput": "Call Mom",
"guidePhoneSend": "Lily will make the call",
"guidePhoneEnd": "Call placed—try other commands",
"guideSmsStart": "Tell Lily: “Send Dad a text: I’ll be home for dinner”",
"guideSmsInput": "Text Dad: I’ll be home for dinner",
"guideSmsSend": "Lily will send the message",
"guideSmsEnd": "Message sent—voice control is convenient",
// Goods pages common footer (placeholders)
'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans',
'copyrightVoitrans': '© 2025 Voitrans Technologies',
// Meeting goods page (placeholders)
'meetingHeaderDesc1':
'Audio recording, transcription, keyword search, and auto summary.',
'meetingHeaderDesc2':
'Suitable for business meetings, class notes, and interview minutes.',
'meetingAutoRecording': 'Auto recording and segmentation',
'meetingSpeakerTagging': 'Speaker labeling',
'meetingLongAudioTranscription': 'Long audio transcription',
'meetingKeyPointSummary': 'Key point extraction',
'meetingTopicNameSearch': 'Search by topic/name',
'meetingTimelineJump': 'Timeline jump',
'meetingExportSummary': 'Export minutes',
'meetingMultiPlatformShare': 'Share across platforms',
'meetingDisclaimer':
'Use in quiet environments; performance depends on microphone and network.',
// Translation goods page (placeholders)
'transHeaderDesc1':
'Echtzeit-Simultandolmetschen und Textübersetzung mit Sprachwiedergabe bei niedriger Latenz.',
'transHeaderDesc2': 'Geeignet für Reisen, Geschäft, Reden und Lehre.',
'translateZhEn': 'Chinesisch-Englisch-Übersetzung',
'lowLatencyVoiceBroadcast': 'Sprachübertragung mit niedriger Latenz',
'multiLangTextTranslation': 'Mehrsprachige Textübersetzung',
'termOptimizationContextPreserve':
'Terminologieoptimierung und Kontextwahrung',
'lexiconTourBusinessLife': 'Lexika für Reise/Geschäft/Alltag',
'personalVocabularyMemory': 'Persönlicher Wortschatzspeicher',
'conversationSubtitleLargeText': 'Konversationsuntertitel / Großtext-Modus',
'colorHighContrast': 'Hoher Farbkontrast',
'transDisclaimer':
'Die Übersetzungsleistung hängt von Mikrofon, Netzwerklatenz und Umgebungsgeräuschen ab.',
'trans_001_name': 'Übersetzung Basis 100',
'trans_002_name': 'Übersetzung Basis 500',
'trans_003_name': 'Übersetzung Basis 1000',
'trans_001_desc': 'Enthält 100 Übersetzungen (Stimme/Text).',
'trans_002_desc': 'Enthält 500 Übersetzungen (Stimme/Text).',
'trans_003_desc': 'Enthält 1000 Übersetzungen (Stimme/Text).',
// VIP goods page (placeholders)
'benefitsOverview': 'Übersicht der Vorteile',
'higherQuota': 'Höheres Nutzungskontingent',
'lowerUnitPrice': 'Niedrigerer Stückpreis',
'priorityService': 'Priorisierter Service',
'exclusiveSupportChannel': 'Dedizierter Supportkanal',
'fastResponse': 'Schnelle Problemreaktion',
'eventsAndDiscounts': 'Veranstaltungen und Rabatte',
'memberExclusiveEvents': 'Exklusive Events für Mitglieder',
'longTermDiscountPlan': 'Langfristiger Rabattplan',
'generalPrivileges': 'Allgemeine Privilegien',
'earlyAccessNewFeatures': 'Frühzeitiger Zugriff auf neue Funktionen',
'crossDeviceSync': 'Geräteübergreifende Synchronisierung',
'vipDisclaimer':
'Die tatsächlichen Vorteile hängen von den Paketdetails ab und können sich mit Versionen ändern.',
};

49
lib/core/translations/language/el_gr.dart

@ -138,7 +138,8 @@ const Map<String, String> elGR = {
"bluetoothInitializationFailure":
"Αποτυχία αρχικοποίησης υπηρεσίας Bluetooth",
"checkingPermissions": "Έλεγχος δικαιωμάτων...",
"lackPermissions": "Απαιτούνται δικαιώματα Bluetooth",
"lackPermissions":
"Απαιτούνται δικαιώματα Bluetooth και πρόσβαση στην τοποθεσία",
"searchingDevice": "Αναζήτηση συσκευών...",
"findConnectedDevice": "Βρέθηκε συνδεδεμένη συσκευή",
"notFound": "Δεν βρέθηκαν συνδεδεμένες συσκευές Bluetooth",
@ -183,22 +184,9 @@ const Map<String, String> elGR = {
"conferenceAssistant": "Βοηθός επιχειρηματικών συναντήσεων",
"conferenceAssistantInfo":
"Καταγραφή πρακτικών σε πραγματικό χρόνο και πολυγλωσσική μετάφραση",
"studyAssistant": "Βοηθός εκμάθησης γλωσσών",
"studyAssistantInfo": "Διόρθωση προφοράς και εξάσκηση ομιλίας",
"travelTranslator": "Μεταφραστής ταξιδιού",
"travelTranslatorInfo":
"Φωνητική μετάφραση σε πραγματικό χρόνο και οδηγός αξιοθέατων",
"beSearching": "Αναζήτηση:",
"noAssistantFound": "Δεν βρέθηκε αντίστοιχος βοηθός AI",
"usageStats": "Στατιστικά χρήσης",
"usageStatsInfo": "Δείτε τα στατιστικά χρήσης της εφαρμογής",
"scene": "Σενάρια",
"youHaveSelected": "Έχετε επιλέξει:",
"newFunction": "Νέες λειτουργίες",
"youChoseTry": "Επιλέξατε να δοκιμάσετε",
"aiSinger": "Λειτουργία τραγουδιστή AI",
"aiSingerInfo":
"Τραγουδήστε οποιοδήποτε τραγούδι με τη φωνή του αγαπημένου σας καλλιτέχνη, ακόμα και τις δικές σας δημιουργίες",
"popularFunction": "Δημοφιλείς λειτουργίες",
"tryNow": "Δοκιμάστε τώρα",
// 商务会议助手页
"startMeeting": "Έναρξη συνάντησης",
@ -214,8 +202,12 @@ const Map<String, String> elGR = {
'meetingTranscript': 'Απομαγνητοφώνηση συνάντησης',
// 设置页
"systemSettings": "Ρυθμίσεις συστήματος",
"premiumMember": "Premium μέλος",
"systemSettings": "Ρυθμίσεις συστήματος", //系统设置
"vipRecharge": "Περιορέωση VIP μέλους", //会员充值
"aiRecharge": "Premium μέλος", //AI充值
"translationRecharge": "Περιορέωση μετάφρασης", //翻译充值
"meetingAssistantRecharge": "Περιορέωση βοηθού συνάντησης", //会议助手充值
"cloudSync": "Περιορέωση συγχρονισμού στο cloud", //云端同步
"joinDevice": "Συνδεδεμένη συσκευή:",
"accountId": "ID λογαριασμού:",
"systemSetting": "Ρυθμίσεις συστήματος",
@ -287,7 +279,7 @@ const Map<String, String> elGR = {
//Agent 模块
// agent View
"XiaoYan": "Xiao Yan",
"Lily": "Lily",
"clearChatHistory": "Εκκαθάριση ιστορικού συνομιλίας",
"online": "Σε σύνδεση",
"inputMessage": "Εισάγετε μήνυμα...",
@ -314,14 +306,13 @@ const Map<String, String> elGR = {
"swipeUpForMore": "Σύρετε προς τα πάνω για περισσότερα",
// Agent controller
'welcomeMessage':
'Γεια σας! Είμαι ο **Xiao Yan**, μπορώ να σας βοηθήσω με:\n\n'
'• Απάντηση σε ερωτήσεις και παροχή πληροφοριών\n\n'
'• Μετάφραση φωνής σε πραγματικό χρόνο\n\n'
'• Προτάσεις μουσικής και podcasts\n\n'
'• Φωνητικές σημειώσεις και υπενθυμίσεις\n\n'
'• Έλεγχος λειτουργιών ακουστικών\n\n'
'Με τι μπορώ να σας βοηθήσω;',
'welcomeMessage': 'Γεια σας! Είμαι ο **Lily**, μπορώ να σας βοηθήσω με:\n\n'
'• Απάντηση σε ερωτήσεις και παροχή πληροφοριών\n\n'
'• Μετάφραση φωνής σε πραγματικό χρόνο\n\n'
'• Προτάσεις μουσικής και podcasts\n\n'
'• Φωνητικές σημειώσεις και υπενθυμίσεις\n\n'
'• Έλεγχος λειτουργιών ακουστικών\n\n'
'Με τι μπορώ να σας βοηθήσω;',
'microphonePermission': 'Μικρόφωνο',
'voiceRecognitionPermissionText':
'Η λειτουργία αναγνώρισης φωνής χρειάζεται πρόσβαση στο μικρόφωνο.',
@ -717,7 +708,7 @@ const Map<String, String> elGR = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Σύζευξη συσκευής",
"connectYourDeepSoundHeadset": "Συνδέστε τα ακουστικά DeepSound",
"connectYourDeepSoundHeadset": "Συνδέστε τα ακουστικά Voitrans",
"bind": "Σύνδεση",
"authorizeBind": "Εξουσιοδότηση σύνδεσης",
"enterCode": "Εισάγετε κωδικό",
@ -777,7 +768,7 @@ const Map<String, String> elGR = {
'retryAuthorization': 'Επανάληψη εξουσιοδότησης',
'pleaseGrantNecessaryPermissions': 'Παραχωρήστε τα απαραίτητα δικαιώματα',
'checkFailedRetry': 'Αποτυχία ελέγχου, δοκιμάστε ξανά',
'pleaseConnectDeepSoundDevice': 'Συνδέστε συσκευή DeepSound',
'pleaseConnectDeepSoundDevice': 'Συνδέστε συσκευή Voitrans',
'verificationFailedRetry': 'Αποτυχία επαλήθευσης, δοκιμάστε ξανά',
'invalidDeviceAddress': 'Μη έγκυρη διεύθυνση συσκευής',
'bleDeviceAssociationFailed': 'Αποτυχία συσχέτισης συσκευής BLE',

354
lib/core/translations/language/en_us.dart

@ -136,7 +136,8 @@ const Map<String, String> enUS = {
"initializing": "Initializing...",
"bluetoothInitializationFailure": "Bluetooth service initialization failed",
"checkingPermissions": "Checking permissions...",
"lackPermissions": "Bluetooth permissions required",
"lackPermissions":
"Enable Bluetooth and location permissions to discover and connect to nearby devices",
"searchingDevice": "Searching for devices...",
"findConnectedDevice": "Found connected device",
"notFound": "No connected Bluetooth devices found",
@ -165,7 +166,7 @@ const Map<String, String> enUS = {
"exploreSlogan": "Smart Earbuds, Infinite Possibilities",
"exploreSlogan1": "Intelligent companion, Infinite Possibilities",
"exploreSlogan2": "Smart glasses, Infinite Possibilities",
"exploreAi": "Explore AI features provided by DeepSound",
"exploreAi": "Explore AI features provided by Voitrans",
"aiFunction": "AI Features",
"allRoundAssistant": "All-round Assistant",
"allRoundAssistantInfo": "Helps solve various problems",
@ -181,21 +182,213 @@ const Map<String, String> enUS = {
"conferenceAssistant": "Business Meeting Assistant",
"conferenceAssistantInfo":
"Real-time minutes recording and multilingual translation",
"studyAssistant": "Language Learning Assistant",
"studyAssistantInfo": "Pronunciation correction and speaking practice",
"travelTranslator": "Travel Translator",
"travelTranslatorInfo": "Real-time voice translation and attraction guides",
"beSearching": "Searching for:",
"noAssistantFound": "No corresponding AI assistant found",
"usageStats": "Usage Statistics",
"usageStatsInfo": "View Your Usage Statistics",
"scene": "Scenarios",
"youHaveSelected": "You've selected:",
"newFunction": "New Features",
"youChoseTry": "You've chosen to try",
"aiSinger": "AI Singer Mode",
"aiSingerInfo":
"Sing any song in your favorite artist's voice, even your own creations",
"popularFunction": "Popular Features",
"tryNow": "Try Now",
/// 用量统计模块
"aiChat": "AI Chat",
"translationStats": "Translation Statistics",
"meetingStats": "Meeting Statistics",
"today": "Today",
"thisWeek": "This Week",
"thisMonth": "This Month",
"history": "History",
"currentSessionStats": "Current Session Stats",
"translationCount": "Translation Count",
"sessionDuration": "Session Duration",
"characters": "Characters",
"recordingDuration": "Recording Duration",
"totalApiCalls": "Total API Calls",
"sessionCount": "Session Count",
"totalCharacters": "Total Characters",
"apiCallStats": "API Call Stats",
"translationApi": "Translation API",
"asr": "ASR",
"tts": "TTS",
// "aiSummary": "AI Summary",
"dataVolumeStats": "Data Volume Stats",
"sourceTextCharacters": "Source Text Characters",
"ttsTextCharacters": "TTS Text Characters",
"effectiveAudioDuration": "Effective Audio Duration",
"totalSessionDuration": "Total Session Duration",
"costStats": "Cost Stats",
"estimatedCost": "Estimated Cost",
"dailyCostThreshold": "Daily Cost Threshold",
"monthlyCostThreshold": "Monthly Cost Threshold",
"usageBehaviorStats": "Usage Behavior Stats",
"mostUsedLanguagePair": "Most-used language pair",
"mostUsedMode": "Most-used mode",
"asrApiCalls": "ASR Calls",
"totalAudioDuration": "Total Audio Duration",
"audioFileSize": "Audio File Size",
"transcriptBytes": "Transcript Bytes",
//通知文案
"loadFailed": "Load Failed",
"statsLoadFailedTryLater":
"Statistics failed to load. Please try again later.",
"cleanupComplete": "Cleanup Complete",
"cleanedOldData": "Cleaned data older than 90 days",
"exportFeature": "Export Feature",
"exportInDevelopment": "Data export is under development",
// 商品页面(AI/翻译/会议)
'availablePackages': 'Available Packages',
'remainingQuota': 'Remaining Quota',
'totalQuota': 'Total Quota',
'remaining': 'Remaining',
'featureDescription': 'Feature Description',
// AI 功能卡片
'musicAndRecommendation': 'Music & Recommendation',
'navigationAndRoutes': 'Navigation & Routes',
'nearbySearch': 'Nearby Search',
'newsInformation': 'News',
'communicationAssistant': 'Communication Assistant',
// 翻译功能卡片
'realtimeTranscription': 'Real-time Transcription',
// 'textTranslation' exists
'sceneLexicon': 'Scenario Glossary',
'subtitleDisplay': 'Subtitles',
// 会议功能卡片
'meetingRecording': 'Meeting Recording',
'transcriptionAndSummary': 'Transcription & Summary',
'keywordSearch': 'Keyword Search',
'collaborationSharing': 'Collaboration & Sharing',
// 商品名称(按ID)
'ai_001_name': 'AI Basic 100',
'ai_002_name': 'AI Basic 500',
'ai_003_name': 'AI Basic 1000',
'meet_001_name': 'Meeting Basic 100',
'meet_002_name': 'Meeting Basic 500',
'meet_003_name': 'Meeting Basic 1000',
'trans_001_name': 'Translation Basic 100',
'trans_002_name': 'Translation Basic 500',
'trans_003_name': 'Translation Basic 1000',
// 商品描述(按ID)
'ai_001_desc': 'Includes 100 uses. Access core AI features.',
'ai_002_desc': 'Includes 500 uses. Access core AI features.',
'ai_003_desc': 'Includes 1000 uses. Access core AI features.',
'meet_001_desc': 'Includes 100 meeting recordings/transcriptions.',
'meet_002_desc': 'Includes 500 meeting recordings/transcriptions.',
'meet_003_desc': 'Includes 1000 meeting recordings/transcriptions.',
'trans_001_desc': 'Includes 100 translations (voice/text).',
'trans_002_desc': 'Includes 500 translations (voice/text).',
'trans_003_desc': 'Includes 1000 translations (voice/text).',
// 商品页通用页脚
'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans',
'iapCustomerServiceQQLabel': 'IAP customer service QQ: @qq',
'copyrightVoitrans': '© 2025 Voitrans Technologies',
// 会议商品页描述
'meetingHeaderDesc1':
'Audio recording, transcription, keyword search, and auto summary to boost meeting efficiency.',
'meetingHeaderDesc2':
'Suitable for business meetings, class notes, and interview minutes.',
'meetingAutoRecording': 'Auto recording and segmentation',
'meetingSpeakerTagging': 'Speaker labeling',
'meetingLongAudioTranscription': 'Long audio transcription',
'meetingKeyPointSummary': 'Key point extraction',
'meetingTopicNameSearch': 'Search by topic/name',
'meetingTimelineJump': 'Timeline jump',
'meetingExportSummary': 'Export minutes',
'meetingMultiPlatformShare': 'Share across platforms',
'meetingDisclaimer':
'Use in quiet environments; performance depends on microphone and network.',
// 同传/翻译商品页描述
'transHeaderDesc1':
'Real-time simultaneous interpretation and text translation with low-latency voice.',
'transHeaderDesc2': 'Suitable for travel, business, speeches, and teaching.',
'translateZhEn': 'Chinese-English translation',
'lowLatencyVoiceBroadcast': 'Low-latency voice broadcast',
'multiLangTextTranslation': 'Multilingual text translation',
'termOptimizationContextPreserve':
'Terminology optimization and context preservation',
'lexiconTourBusinessLife': 'Travel/Business/Life lexicons',
'personalVocabularyMemory': 'Personal vocabulary memory',
'conversationSubtitleLargeText': 'Conversation subtitles / Large-text mode',
'colorHighContrast': 'High color contrast',
'transDisclaimer':
'Translation performance depends on microphone, network latency, and ambient noise.',
// AI 商品页描述
'aiHeaderDesc1':
'Longer conversation quota, more tool calls, extended context length.',
'aiHeaderDesc2':
'Suitable for agent Q&A, summarization, analysis, and task execution.',
'musicSearchPlaybackControl': 'Music library search and playback control',
'smartPlaylistAndSimilarRecommendations':
'Smart playlist and similar song recommendations',
'routePlanningAndCongestionAvoidance':
'Route planning and congestion avoidance',
'voiceBroadcastAndWaypoints': 'Voice broadcast and waypoint settings',
'realTimeWeatherForecast': 'Real-time weather and forecast',
'clothingAdviceAndTravelReminders': 'Clothing advice and travel reminders',
'poiSearchFoodGasParking': 'POI search: dining / gas / parking',
'ratingsHoursAndDirectRoutes': 'Ratings, business hours, and direct routing',
'hotNewsAndTopicOverview': 'Hot news and topic overview',
'longArticleSummariesAndKeyPoints': 'Long-article summaries and key points',
'helpCallAndSMS': 'Help with calls and SMS',
'templatedMessagesAndScheduleReminders':
'Template messages and schedule reminders',
'aiDisclaimer':
'Features depend on device permissions, service availability, and network conditions.',
// 会员商品页
'benefitsOverview': 'Benefits overview',
'higherQuota': 'Higher usage quota',
'lowerUnitPrice': 'Lower unit price',
'priorityService': 'Priority service',
'exclusiveSupportChannel': 'Dedicated support channel',
'fastResponse': 'Fast issue response',
'eventsAndDiscounts': 'Events and discounts',
'memberExclusiveEvents': 'Member-exclusive events',
'longTermDiscountPlan': 'Long-term discount plan',
'generalPrivileges': 'General privileges',
'earlyAccessNewFeatures': 'Early access to new features',
'crossDeviceSync': 'Cross-device sync',
'vipDisclaimer':
'Actual benefits depend on the package details and may change with versions.',
// 新手引导 / Onboarding
'skip': 'Skip',
'next': 'Next',
'sayLilyHint': 'Say "Lily Lily" to the mic',
'imHere': 'I’m here~',
'guideWelcomeWakeAI': 'Welcome to Voitrans! First, wake your AI “Lily”.',
'aiReplyCompleted': 'Lily has finished the reply!',
'aiThinking': 'Lily is thinking…',
'guideAwakenSuccess': 'Great! Lily is awake—ask it to help.',
'confirmInput': 'Confirm Input',
'guideClickSendPrefix': 'Tap send, ',
// AI 引导步骤
'guideWeatherStart': 'Tell Lily: “What’s the weather today?”',
'guideWeatherInput': 'What’s the weather today?',
'guideWeatherSend': 'Lily will report the weather in real time',
'guideWeatherEnd': 'Lily can report weather live—try other commands',
'guideMusicStart': 'Tell Lily: “Play some rock music”',
'guideMusicInput': 'Play some rock music',
'guideMusicSend': 'Lily will find music for you',
'guideMusicEnd': 'Lily found music—try other commands',
'guideNavStart': 'Tell Lily: “Navigate to Shenzhen Airport”',
'guideNavInput': 'Navigate to Shenzhen Airport',
'guideNavSend': 'Lily will plan the route',
'guideNavEnd': 'Navigation set—try other commands',
'guideMeetingStart':
'Tell Lily: “Create a meeting reminder for 3pm tomorrow”',
'guideMeetingInput': 'Create a meeting reminder for 3pm tomorrow',
'guideMeetingSend': 'Lily will create a meeting reminder',
'guideMeetingEnd': 'Reminder created—try other commands',
'guidePhoneStart': 'Tell Lily: “Call Mom”',
'guidePhoneInput': 'Call Mom',
'guidePhoneSend': 'Lily will make the call',
'guidePhoneEnd': 'Call placed—try other commands',
'guideSmsStart': 'Tell Lily: “Send Dad a text: I’ll be home for dinner”',
'guideSmsInput': 'Text Dad: I’ll be home for dinner',
'guideSmsSend': 'Lily will send the message',
'guideSmsEnd': 'Message sent—voice control is convenient',
// 商务会议助手页
"startMeeting": "Start Meeting",
@ -438,8 +631,16 @@ const Map<String, String> enUS = {
'inputAttendees': 'Enter Attendees',
// 设置页
"systemSettings": "System Settings",
"premiumMember": "Premium Membership",
"systemSettings": "System Settings", //系统设置
"vipRecharge": "VIP Recharge", //会员充值
"aiRecharge": "AI Recharge", //AI充值
"translationRecharge": "Translation Recharge", //翻译充值
"meetingAssistantRecharge": "Meeting Recharge", //会议充值
"cloudSync": "Cloud Sync Recharge", //云端同步
"memberService": "Member Service",
"bindRewardTitle": "Rewards",
"bindRewardSimpleDesc":
"First bind device reward has been issued. Tap OK to close.",
"joinDevice": "Connected device:",
"accountId": "Account ID:",
"systemSetting": "System Settings",
@ -517,7 +718,7 @@ const Map<String, String> enUS = {
// Agent模块
//Agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Clear Chat History",
"online": "Online",
"inputMessage": "Type a message...",
@ -546,9 +747,9 @@ const Map<String, String> enUS = {
"voice_interrupt": "Interrupt", // 语音打断
// 预设提示词
"presetMusic": "Play some music", // Play some music
"presetNavigation": "Navigation to", // Navigation
"presetWeather": "Today's weather", // Weather
"presetMusic": "Play some music",
"presetNavigation": "Navigation to",
"presetWeather": "Today's weather",
"presetNews": "Today's news", // News
"presetFood": "Nearby food", // Food
"playSomeMusic": "Play some popular music", // 播放一些流行音乐
@ -558,7 +759,7 @@ const Map<String, String> enUS = {
"nearbyFood": "What delicious food is nearby?", // 美食
// Agent controller
'welcomeMessage': 'Hello! I\'m **Xiaoyan**, I can help you:\n\n'
'welcomeMessage': 'Hello! I\'m **Lily**, I can help you:\n\n'
'• Answer questions and provide information\n\n'
'• Real-time voice translation\n\n'
'• Recommend music and podcasts\n\n'
@ -603,7 +804,7 @@ const Map<String, String> enUS = {
//Message_bubble
'generatedByAi': 'Generated by AI',
//music_card
//音乐卡片 music_card
'recommendedMusic': 'Here are some recommended music:',
'playList': 'Playlist',
'moreMusic': 'More music',
@ -618,10 +819,10 @@ const Map<String, String> enUS = {
'currentLocation': 'Current Location', // 当前位置
'approximate': 'About ', // 大约
'enterRoad': ' enter ', // 进入道路
"driving": "Driving",
"walking": "Walking",
"bicycling": "Cycling",
"tsransit": "Transit",
"driving": "Driving", // 驾驶
"walking": "Walking", // 步行
"bicycling": "Cycling", // 骑行
"tsransit": "Transit", // 公交
//天气卡片 weather_card
'weatherQuery': 'Weather Query:',
@ -653,6 +854,17 @@ const Map<String, String> enUS = {
"friday": "Fri",
"saturday": "Sat",
"sunday": "Sun",
// First bind rewards dialog
"firstBindRewardTitle": "Welcome Reward",
"firstBindRewardDesc": "You've received binding rewards.",
"vipLevelLabel": "VIP Level:",
"expiryLabel": "Expiration:",
"notActivated": "Not activated",
"aiChatCreditsLabel": "AI Chat Credits:",
"translationCreditsLabel": "Translation Credits:",
"meetingCreditsLabel": "Meeting Credits:",
"ok": "OK",
// 天气描述
"sunny": "Sunny",
"partlyCloudy": "Partly Cloudy",
@ -982,8 +1194,9 @@ const Map<String, String> enUS = {
"pictureTranslation": "Picture Translation",
"textTranslation": "Text Translation",
// 翻译主页
// 翻译主页 (translation_view.dart)
"translationHistory": "Translation History",
"historyRecords": "History Records",
"enableRecording": "Enable Recording",
"viewAudioFiles": "View Audio Files",
"headsetUser": "Headset User",
@ -992,13 +1205,21 @@ const Map<String, String> enUS = {
"selectTargetLanguage": "Select Target Language",
"me": "Me", //我
"counterPart": "Counterpart", //对方
"bluetoothCallStateError":
"Please make sure the Bluetooth headset is connected to the phone and in a call state", //请确保蓝牙耳机已连接到手机并处于通话状态
// 通用对话按钮与选项(用于统一语言选择弹窗等)
// 翻译键代表的中文文本内容:取消/确认/自动检测
"autoDetect": "Auto Detect",
// Text translation & language detection
"languageDetectionFailed": "Language detection failed",
"translationFailed": "Translation failed",
"pleaseInputText": "Please input text",
"textTooLong": "Text too long, max 5000 characters",
// 翻译历史页
"noTranslationHistory": "No translation history",
"clearResults": "Clear Results",
"clearHistory": "Clear History",
"clearHistoryConfirm":
"Are you sure you want to clear all translation history? This action cannot be undone.",
@ -1007,7 +1228,58 @@ const Map<String, String> enUS = {
"deleteSessionConfirm":
"Are you sure you want to delete all translation records for this session? This action cannot be undone.",
// 翻译音频文件列表页
// Picture Translation module
"selectImageSource": "Select Image Source",
"imagePreview": "Image Preview",
"translationResult": "Translation Result",
"recognitionResult": "Recognition Result",
"translatedImagePreview": "Translated Image Preview",
"translatedImageLoadFailed": "Failed to load translated image",
"pleaseSelectImage": "Please select an image",
"imageLoadFailed": "Image load failed",
"imageQuality": "Image Quality",
"maxSize": "Max Size",
"close": "Close",
"setImageQuality": "Set Image Quality",
"currentQuality": "Current quality: @value%",
"setMaxSize": "Set Max Size",
"currentMaxSize": "Current: @pxpx",
"waitingForAction": "Waiting for action",
"pleaseSelectImageToStart": "Please select an image to start",
"chooseImage": "Choose Image",
"openingCamera": "Opening camera...",
"openingPhotoAlbum": "Opening photo album...",
"cancelled": "Cancelled",
"userCancelledSelection": "User cancelled selection",
"translatingImage": "Translating Image",
"callingImageTranslateService": "Calling image translation service...",
"savingRecord": "Saving Record",
"savingTranslationResult": "Saving translation result...",
"translationCompleted": "Translation Completed",
"allStepsCompleted": "All steps completed",
"processingFailed": "Processing Failed",
"imageProcessingOrTranslationFailed":
"Image processing or translation failed. Please retry.\nError: {error}",
"imageTooLarge": "Image size exceeds 4MB limit",
"imageTooLargeHint":
"Image size exceeds 4MB. Reduce quality or dimensions and retry",
"emptyTranslationResult": "Image translation API returned empty result",
"imageTranslationFailedTryLater":
"Image translation failed. Network issue or rate limit. Please try later",
"imageTranslationApiException":
"Image translation API exception. Check network and retry",
"permissionRequired": "Permission Required",
"cameraPermissionRequired": "Camera permission required to take photos",
"photoAlbumPermissionRequired":
"Photo album permission required to pick images",
"translationDetails": "Translation Details",
"originalImage": "Original Image",
"sourceLanguage": "Source Language",
"targetLanguage": "Target Language",
"translationTime": "Translation Time",
"shareInDevelopment": "Sharing feature under development",
// 翻译录音文件列表页
"translateAudioFiles": "Translate Audio Files",
"noAudioFiles": "No audio files",
"calculating": "Calculating...",
@ -1053,7 +1325,7 @@ const Map<String, String> enUS = {
"autoInputCode": "Auto Input Code",
"skipBinding": "Skip Binding",
"rescan": "Rescan",
"skip": "Skip",
"verifyingDevice": "Verifying device...",
"confirmBinding": "Confirm Binding",
"associatingDevice": "Associating device...",
@ -1064,7 +1336,7 @@ const Map<String, String> enUS = {
"readyToPair": "Ready to pair",
"preparingPairingEnvironment": "Preparing pairing environment...",
"connectDeepSoundViaSystemBluetooth":
"Please connect DeepSound device via system Bluetooth first",
"Please connect Voitrans device via system Bluetooth first",
"deviceBindingConfirm": "Device binding confirmation...",
"establishingDeviceAssociation": "Establishing device association...",
"waitingCompletePairing": "Please wait, completing pairing...",
@ -1073,7 +1345,7 @@ const Map<String, String> enUS = {
// 配对错误状态文本
"ensureConnectedDeepSoundDevice":
"Please ensure connected device is DeepSound",
"Please ensure connected device is Voitrans",
"deviceAlreadyBoundToOtherAccount":
"This device is already bound to another account",
"deviceAssociationFailed": "Device association failed, please retry",
@ -1105,7 +1377,7 @@ const Map<String, String> enUS = {
'retryAuthorization': 'Retry Authorization',
'pleaseGrantNecessaryPermissions': 'Please grant necessary permissions',
'checkFailedRetry': 'Check failed, please retry',
'pleaseConnectDeepSoundDevice': 'Please connect DeepSound device',
'pleaseConnectDeepSoundDevice': 'Please connect Voitrans device',
'verificationFailedRetry': 'Verification failed, please retry',
'invalidDeviceAddress': 'Invalid device address',
'bleDeviceAssociationFailed': 'BLE device association failed',
@ -1216,4 +1488,18 @@ const Map<String, String> enUS = {
"justNow": "Just now",
"minutesAgo": "@minutes minutes ago",
"yesterday": "Yesterday",
// Time extensions (used by picture translation)
"daysAgo": "@days days ago",
"hoursAgo": "@hours hours ago",
//补充
"insufficientIntegral": "Insufficient integral",
//余额不足弹窗
"insufficientBalanceDesc":
'Insufficient balance, please go to the corresponding recharge page to recharge.',
"recharge": 'Go to Recharge',
// 会员到期提示(中文注释)
"aiMemberExpiredDesc":
'AI membership expired, please go to the membership recharge page to renew.',
};

70
lib/core/translations/language/es_es.dart

@ -138,7 +138,8 @@ const Map<String, String> esES = {
"bluetoothInitializationFailure":
"Fallo en la inicialización del servicio Bluetooth",
"checkingPermissions": "Verificando permisos...",
"lackPermissions": "Faltan permisos de Bluetooth",
"lackPermissions":
"Habilita permisos de Bluetooth y ubicación para descubrir y conectar dispositivos cercanos",
"searchingDevice": "Buscando dispositivos...",
"findConnectedDevice": "Dispositivo conectado encontrado",
"notFound": "No se encontraron dispositivos Bluetooth conectados",
@ -184,22 +185,9 @@ const Map<String, String> esES = {
"conferenceAssistant": "Asistente de reuniones de negocios",
"conferenceAssistantInfo":
"Grabación de actas en tiempo real y traducción multiidioma",
"studyAssistant": "Asistente de aprendizaje de idiomas",
"studyAssistantInfo": "Corrección de pronunciación y práctica de habla",
"travelTranslator": "Traductor de viajes",
"travelTranslatorInfo":
"Traducción de voz en tiempo real y guía de atracciones turísticas",
"beSearching": "Buscando:",
"noAssistantFound": "No se encontró asistente de IA correspondiente",
"usageStats": "Estadísticas de uso",
"usageStatsInfo": "Consulte las estadísticas de uso de la aplicación",
"scene": "Escenarios",
"youHaveSelected": "Has seleccionado:",
"newFunction": "Nuevas funciones",
"youChoseTry": "Elegiste probar",
"aiSinger": "Modo cantante de IA",
"aiSingerInfo":
"Canta cualquier canción con la voz de tu artista favorito, incluso tus propias creaciones",
"popularFunction": "Funciones populares",
"tryNow": "Probar ahora",
// 商务会议助手页
"startMeeting": "Iniciar reunión",
@ -215,8 +203,12 @@ const Map<String, String> esES = {
'meetingTranscript': 'Transcripción de reunión',
// 设置页
"systemSettings": "Configuración del sistema",
"premiumMember": "Miembro premium",
"systemSettings": "Configuración del sistema", //系统设置
"vipRecharge": "Recarga de VIP", //会员充值
"aiRecharge": "Miembro premium", //AI充值
"translationRecharge": "Recarga de traducción", //翻译充值
"meetingAssistantRecharge": "Recarga de asistente de reunión", //会议助手充值
"cloudSync": "Recarga de sincronización en la nube", //云端同步
"joinDevice": "Dispositivo conectado:",
"accountId": "ID de cuenta:",
"systemSetting": "Configuración del sistema",
@ -289,7 +281,7 @@ const Map<String, String> esES = {
//Agent 模块
// agent View
"XiaoYan": "Xiao Yan",
"Lily": "Lily",
"clearChatHistory": "Limpiar historial de chat",
"online": "En línea",
"inputMessage": "Ingresa mensaje...",
@ -316,7 +308,7 @@ const Map<String, String> esES = {
"swipeUpForMore": "Desliza hacia arriba para más",
// Agent controller
'welcomeMessage': '¡Hola! Soy **Xiao Yan**, puedo ayudarte con:\n\n'
'welcomeMessage': '¡Hola! Soy **Lily**, puedo ayudarte con:\n\n'
'• Responder preguntas y proporcionar información\n\n'
'• Traducción de voz en tiempo real\n\n'
'• Recomendaciones de música y podcasts\n\n'
@ -718,7 +710,7 @@ const Map<String, String> esES = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Emparejamiento de dispositivo",
"connectYourDeepSoundHeadset": "Conecta tus auriculares DeepSound",
"connectYourDeepSoundHeadset": "Conecta tus auriculares Voitrans",
"bind": "Vincular",
"authorizeBind": "Autorizar vinculación",
"enterCode": "Ingresa código",
@ -779,7 +771,7 @@ const Map<String, String> esES = {
'retryAuthorization': 'Reintentar autorización',
'pleaseGrantNecessaryPermissions': 'Otorga los permisos necesarios',
'checkFailedRetry': 'Verificación fallida, inténtalo de nuevo',
'pleaseConnectDeepSoundDevice': 'Conecta dispositivo DeepSound',
'pleaseConnectDeepSoundDevice': 'Conecta dispositivo Voitrans',
'verificationFailedRetry': 'Verificación fallida, inténtalo de nuevo',
'invalidDeviceAddress': 'Dirección de dispositivo inválida',
'bleDeviceAssociationFailed': 'Fallo en la asociación del dispositivo BLE',
@ -874,4 +866,38 @@ const Map<String, String> esES = {
"乌尔都语": "Urdu",
"波斯语": "Persa",
"斯瓦希里语": "Suajili",
// Guide overlay keys (placeholders in English)
"sayLilyHint": "Say \"Lily Lily\" to the mic",
"imHere": "I’m here~",
"guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Lily”.",
"aiReplyCompleted": "Lily has finished the reply!",
"aiThinking": "Lily is thinking…",
"guideAwakenSuccess": "Great! Lily is awake—ask it to help.",
"confirmInput": "Confirm Input",
"guideClickSendPrefix": "Tap send, ",
"guideWeatherStart": "Tell Lily: “What’s the weather today?”",
"guideWeatherInput": "What’s the weather today?",
"guideWeatherSend": "Lily will report the weather in real time",
"guideWeatherEnd": "Lily can report weather live—try other commands",
"guideMusicStart": "Tell Lily: “Play some rock music”",
"guideMusicInput": "Play some rock music",
"guideMusicSend": "Lily will find music for you",
"guideMusicEnd": "Lily found music—try other commands",
"guideNavStart": "Tell Lily: “Navigate to Shenzhen Airport”",
"guideNavInput": "Navigate to Shenzhen Airport",
"guideNavSend": "Lily will plan the route",
"guideNavEnd": "Navigation set—try other commands",
"guideMeetingStart":
"Tell Lily: “Create a meeting reminder for 3pm tomorrow”",
"guideMeetingInput": "Create a meeting reminder for 3pm tomorrow",
"guideMeetingSend": "Lily will create a meeting reminder",
"guideMeetingEnd": "Reminder created—try other commands",
"guidePhoneStart": "Tell Lily: “Call Mom”",
"guidePhoneInput": "Call Mom",
"guidePhoneSend": "Lily will make the call",
"guidePhoneEnd": "Call placed—try other commands",
"guideSmsStart": "Tell Lily: “Send Dad a text: I’ll be home for dinner”",
"guideSmsInput": "Text Dad: I’ll be home for dinner",
"guideSmsSend": "Lily will send the message",
"guideSmsEnd": "Message sent—voice control is convenient",
};

34
lib/core/translations/language/et_ee.dart

@ -135,7 +135,7 @@ const Map<String, String> etEE = {
"bluetoothInitializationFailure":
"Bluetooth teenuse lähtestamine ebaõnnestus",
"checkingPermissions": "Lubade kontrollimine...",
"lackPermissions": "Puuduvad Bluetooth load",
"lackPermissions": "Puuduvad Bluetooth lubad ja luba kasutamiseks loetakse",
"searchingDevice": "Seadmete otsimine...",
"findConnectedDevice": "Leitud ühendatud seade",
"notFound": "Ühendatud Bluetooth seadmeid ei leitud",
@ -180,21 +180,9 @@ const Map<String, String> etEE = {
"conferenceAssistant": "Ärikoosoleku assistent",
"conferenceAssistantInfo":
"Reaalajas protokolli salvestamine ja mitmekeelne tõlge",
"studyAssistant": "Keeleõppe assistent",
"studyAssistantInfo": "Häälduse parandamine ja kõne harjutamine",
"travelTranslator": "Reisi tõlkija",
"travelTranslatorInfo": "Reaalajas häältõlge ja vaatamisväärsuste giid",
"beSearching": "Otsimine:",
"noAssistantFound": "Vastavat AI assistenti ei leitud",
"usageStats": "Kasutamise statistika",
"usageStatsInfo": "Näita sovelluksen kasutamise statistikat",
"scene": "Stsenaariumid",
"youHaveSelected": "Oled valinud:",
"newFunction": "Uued funktsioonid",
"youChoseTry": "Valisid proovida",
"aiSinger": "AI laulja režiim",
"aiSingerInfo":
"Laula mis tahes laulu oma lemmikartisti häälega, isegi oma loominguga",
"popularFunction": "Populaarsed funktsioonid",
"tryNow": "Proovi kohe",
// 商务会议助手页
"startMeeting": "Alusta koosolekut",
@ -210,8 +198,12 @@ const Map<String, String> etEE = {
'meetingTranscript': 'Koosoleku transkriptsioon',
// 设置页
"systemSettings": "Süsteemi seaded",
"premiumMember": "Premium liige",
"systemSettings": "Süsteemi seaded", //系统设置
"vipRecharge": "VIP liige varundus", //会员充值
"aiRecharge": "Premium liige", //AI充值
"translationRecharge": "Tõlke varundus", //翻译充值
"meetingAssistantRecharge": "Koosoleku assistendi varundus", //会议助手充值
"cloudSync": "Pääsyvaraus cloud-synkronointiin", //云端同步
"joinDevice": "Ühendatud seade:",
"accountId": "Konto ID:",
"systemSetting": "Süsteemi seaded",
@ -281,7 +273,7 @@ const Map<String, String> etEE = {
//Agent 模块
// agent View
"XiaoYan": "Xiao Yan",
"Lily": "Lily",
"clearChatHistory": "Tühjenda vestluse ajalugu",
"online": "Võrgus",
"inputMessage": "Sisesta sõnum...",
@ -308,7 +300,7 @@ const Map<String, String> etEE = {
"swipeUpForMore": "Libista üles rohkema jaoks",
// Agent controller
'welcomeMessage': 'Tere! Olen **Xiao Yan**, saan sind aidata:\n\n'
'welcomeMessage': 'Tere! Olen **Lily**, saan sind aidata:\n\n'
'• Küsimustele vastamine ja info andmine\n\n'
'• Reaalajas häältõlge\n\n'
'• Muusika ja podcastide soovitused\n\n'
@ -700,7 +692,7 @@ const Map<String, String> etEE = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Seadme sidumine",
"connectYourDeepSoundHeadset": "Ühenda oma DeepSound kõrvaklapid",
"connectYourDeepSoundHeadset": "Ühenda oma Voitrans kõrvaklapid",
"bind": "Seo",
"authorizeBind": "Autoriseeri sidumine",
"enterCode": "Sisesta kood",
@ -756,7 +748,7 @@ const Map<String, String> etEE = {
'retryAuthorization': 'Proovi autoriseerimist uuesti',
'pleaseGrantNecessaryPermissions': 'Anna vajalikud load',
'checkFailedRetry': 'Kontrollimine ebaõnnestus, proovi uuesti',
'pleaseConnectDeepSoundDevice': 'Ühenda DeepSound seade',
'pleaseConnectDeepSoundDevice': 'Ühenda Voitrans seade',
'verificationFailedRetry': 'Kontrollimine ebaõnnestus, proovi uuesti',
'invalidDeviceAddress': 'Vigane seadme aadress',
'bleDeviceAssociationFailed': 'BLE seadme seostamine ebaõnnestus',

37
lib/core/translations/language/fa_ir.dart

@ -133,7 +133,8 @@ const Map<String, String> faIR = {
"initializing": "در حال آماده‌سازی...",
"bluetoothInitializationFailure": "آماده‌سازی سرویس بلوتوث ناموفق بود",
"checkingPermissions": "در حال بررسی مجوزها...",
"lackPermissions": "مجوزهای بلوتوث مورد نیاز است",
"lackPermissions":
"مجوزهای بلوتوث مورد نیاز است و دسترسی به لوکیشن نیز لازم است",
"searchingDevice": "در حال جستجوی دستگاه‌ها...",
"findConnectedDevice": "دستگاه متصل پیدا شد",
"notFound": "دستگاه بلوتوث متصلی پیدا نشد",
@ -162,7 +163,7 @@ const Map<String, String> faIR = {
"exploreSlogan": "ایربادهای هوشمند، امکانات بی‌پایان",
"exploreSlogan1": "همراه هوشمند، امکانات بی‌پایان",
"exploreSlogan2": "عینک هوشمند، امکانات بی‌پایان",
"exploreAi": "کاوش ویژگی‌های هوش مصنوعی ارائه‌شده توسط DeepSound",
"exploreAi": "کاوش ویژگی‌های هوش مصنوعی ارائه‌شده توسط Voitrans",
"aiFunction": "ویژگی‌های هوش مصنوعی",
"allRoundAssistant": "دستیار همه‌کاره",
"allRoundAssistantInfo": "به حل مشکلات مختلف کمک می‌کند",
@ -177,21 +178,9 @@ const Map<String, String> faIR = {
"healthConsultantInfo": "ویژگی‌های بیشتر چت هوش مصنوعی",
"conferenceAssistant": "دستیار جلسات کاری",
"conferenceAssistantInfo": "ضبط صورت‌جلسه همزمان و ترجمه چندزبانه",
"studyAssistant": "دستیار یادگیری زبان",
"studyAssistantInfo": "تصحیح تلفظ و تمرین مکالمه",
"travelTranslator": "مترجم سفر",
"travelTranslatorInfo": "ترجمه صوتی همزمان و راهنمای جاذبه‌ها",
"beSearching": "در حال جستجو برای:",
"noAssistantFound": "دستیار هوش مصنوعی مورد نظر یافت نشد",
"usageStats": "استفاده از خدمات",
"usageStatsInfo": "دیدن آمار مصرف سرویس‌ها",
"scene": "سناریوها",
"youHaveSelected": "شما انتخاب کردید:",
"newFunction": "ویژگی‌های جدید",
"youChoseTry": "شما انتخاب کردید که امتحان کنید",
"aiSinger": "حالت خواننده هوش مصنوعی",
"aiSingerInfo":
"هر آهنگی را با صدای هنرمند مورد علاقه خود بخوانید، حتی ساخته‌های خودتان",
"popularFunction": "ویژگی‌های محبوب",
"tryNow": "اکنون امتحان کنید",
// 商务会议助手页
"startMeeting": "شروع جلسه",
@ -428,8 +417,12 @@ const Map<String, String> faIR = {
'inputAttendees': 'ورود شرکت‌کنندگان',
// 设置页
"systemSettings": "تنظیمات سیستم",
"premiumMember": "عضویت ویژه",
"systemSettings": "تنظیمات سیستم", //系统设置
"vipRecharge": "شارژ عضویت ویژه", //会员充值
"aiRecharge": "عضویت ویژه", //AI充值
"translationRecharge": "شارژ ترجمه", //翻译充值
"meetingAssistantRecharge": "شارژ کمک‌کننده جلسه", //会议助手充值
"cloudSync": "شارژ همگام‌سازی ابری", //云端同步
"joinDevice": "دستگاه متصل:",
"accountId": "شناسه حساب:",
"systemSetting": "تنظیمات سیستم",
@ -498,7 +491,7 @@ const Map<String, String> faIR = {
// Agent模块
//Agent View
"XiaoYan": "شیائویان",
"Lily": "Lily",
"clearChatHistory": "پاک کردن تاریخچه چت",
"online": "آنلاین",
"inputMessage": "پیامی تایپ کنید...",
@ -1035,7 +1028,7 @@ const Map<String, String> faIR = {
"readyToPair": "آماده برای جفت‌سازی",
"preparingPairingEnvironment": "در حال آماده‌سازی محیط جفت‌سازی...",
"connectDeepSoundViaSystemBluetooth":
"لطفاً ابتدا دستگاه DeepSound را از طریق بلوتوث سیستم متصل کنید",
"لطفاً ابتدا دستگاه Voitrans را از طریق بلوتوث سیستم متصل کنید",
"deviceBindingConfirm": "تأیید اتصال دستگاه...",
"establishingDeviceAssociation": "در حال برقراری ارتباط دستگاه...",
"waitingCompletePairing": "لطفاً صبر کنید، در حال تکمیل جفت‌سازی...",
@ -1044,7 +1037,7 @@ const Map<String, String> faIR = {
// 配对错误状态文本
"ensureConnectedDeepSoundDevice":
"لطفاً اطمینان حاصل کنید که دستگاه متصل DeepSound است",
"لطفاً اطمینان حاصل کنید که دستگاه متصل Voitrans است",
"deviceAlreadyBoundToOtherAccount":
"این دستگاه قبلاً به حساب دیگری متصل شده است",
"deviceAssociationFailed": "ارتباط دستگاه ناموفق بود، لطفاً دوباره تلاش کنید",
@ -1071,7 +1064,7 @@ const Map<String, String> faIR = {
'retryAuthorization': 'تلاش مجدد برای مجوز',
'pleaseGrantNecessaryPermissions': 'لطفاً مجوزهای لازم را اعطا کنید',
'checkFailedRetry': 'بررسی ناموفق بود، لطفاً دوباره تلاش کنید',
'pleaseConnectDeepSoundDevice': 'لطفاً دستگاه DeepSound را متصل کنید',
'pleaseConnectDeepSoundDevice': 'لطفاً دستگاه Voitrans را متصل کنید',
'verificationFailedRetry': 'تأیید ناموفق بود، لطفاً دوباره تلاش کنید',
'invalidDeviceAddress': 'آدرس دستگاه نامعتبر است',
'bleDeviceAssociationFailed': 'ارتباط دستگاه BLE ناموفق بود',

38
lib/core/translations/language/fi_fi.dart

@ -136,7 +136,8 @@ const Map<String, String> fiFI = {
"initializing": "Alustetaan...",
"bluetoothInitializationFailure": "Bluetooth-palvelun alustus epäonnistui",
"checkingPermissions": "Tarkistetaan käyttöoikeuksia...",
"lackPermissions": "Bluetooth-käyttöoikeudet puuttuvat",
"lackPermissions":
"Bluetooth-käyttöoikeudet puuttuvat ja lokaatioon pääsy on tarpeen",
"searchingDevice": "Etsitään laitteita...",
"findConnectedDevice": "Yhdistetty laite löytyi",
"notFound": "Yhdistettyä Bluetooth-laitetta ei löytynyt",
@ -181,22 +182,9 @@ const Map<String, String> fiFI = {
"conferenceAssistant": "Yrityskokousavustaja",
"conferenceAssistantInfo":
"Reaaliaikainen pöytäkirjan pito, monikielinen käännös",
"studyAssistant": "Kielenoppimisavustaja",
"studyAssistantInfo": "Ääntämisen korjaus, reaaliaikainen puheharjoittelu",
"travelTranslator": "Matkakäännösavustaja",
"travelTranslatorInfo":
"Reaaliaikainen puhekäännös, matkailukohteiden esittely",
"beSearching": "Etsitään:",
"noAssistantFound": "Vastaavaa AI-avustajaa ei löytynyt",
"usageStats": "Käyttöstatistiikka",
"usageStatsInfo": "Näytä sovelluksen käytön statistiikka",
"scene": "Skenaario",
"youHaveSelected": "Olet valinnut:",
"newFunction": "Uusi toiminto",
"youChoseTry": "Valitsit kokeilla",
"aiSinger": "AI-laulaja-tila",
"aiSingerInfo":
"Laula mikä tahansa kappale suosikkilaulajasi äänellä, jopa omat sävellyksesi",
"popularFunction": "Suositut toimintoskenaariot",
"tryNow": "Kokeile nyt",
// 商务会议助手页
"startMeeting": "Aloita kokous",
@ -212,8 +200,12 @@ const Map<String, String> fiFI = {
'meetingTranscript': 'Kokouksen transkriptio',
// 设置页
"systemSettings": "Järjestelmäasetukset",
"premiumMember": "Premium-jäsen",
"systemSettings": "Järjestelmäasetukset", //系统设置
"vipRecharge": "Premium-jäsenvaraus", //会员充值
"aiRecharge": "Premium-jäsen", //AI充值
"translationRecharge": "Käännösvaraus", //翻译充值
"meetingAssistantRecharge": "Kokousavustajan varaus", //会议助手充值
"cloudSync": "Pääsyvaraus cloud-synkronointiin", //云端同步
"joinDevice": "Yhdistetty laite:",
"accountId": "Tilin tunnus:",
"systemSetting": "Järjestelmäasetukset",
@ -283,7 +275,7 @@ const Map<String, String> fiFI = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Tyhjennä keskusteluhistoria",
"online": "Online",
"inputMessage": "Kirjoita viesti...",
@ -310,7 +302,7 @@ const Map<String, String> fiFI = {
"swipeUpForMore": "Pyyhkäise ylös nähdäksesi lisää",
// Agent controller
'welcomeMessage': 'Hei! Olen **XiaoYan**, voin auttaa sinua:\n\n'
'welcomeMessage': 'Hei! Olen **Lily**, voin auttaa sinua:\n\n'
'• Vastaamaan kysymyksiin ja antamaan tietoa\n\n'
'• Reaaliaikaisessa puhekäännöksessä\n\n'
'• Suosittelemaan musiikkia ja podcasteja\n\n'
@ -697,7 +689,7 @@ const Map<String, String> fiFI = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Laitteen paritus",
"connectYourDeepSoundHeadset": "Yhdistä DeepSound-kuulokkeesi",
"connectYourDeepSoundHeadset": "Yhdistä Voitrans-kuulokkeesi",
"bind": "Sido",
"authorizeBind": "Valtuuta sidonta",
"enterCode": "Anna koodi",
@ -715,7 +707,7 @@ const Map<String, String> fiFI = {
"readyToPair": "Valmis paritukseen",
"preparingPairingEnvironment": "Valmistellaan paritusympäristöä...",
"connectDeepSoundViaSystemBluetooth":
"Yhdistä ensin DeepSound-laitteeseen järjestelmän Bluetoothin kautta",
"Yhdistä ensin Voitrans-laitteeseen järjestelmän Bluetoothin kautta",
"deviceBindingConfirm": "Laitteen sidonnan vahvistus...",
"establishingDeviceAssociation": "Luodaan laiteyhteyttä...",
"waitingCompletePairing": "Odota, paritus on valmis...",
@ -750,7 +742,7 @@ const Map<String, String> fiFI = {
'retryAuthorization': 'Yritä valtuutusta uudelleen',
'pleaseGrantNecessaryPermissions': 'Myönnä tarvittavat käyttöoikeudet',
'checkFailedRetry': 'Tarkistus epäonnistui, yritä uudelleen',
'pleaseConnectDeepSoundDevice': 'Yhdistä DeepSound-laite',
'pleaseConnectDeepSoundDevice': 'Yhdistä Voitrans-laite',
'verificationFailedRetry': 'Vahvistus epäonnistui, yritä uudelleen',
'invalidDeviceAddress': 'Virheellinen laiteosoite',
'bleDeviceAssociationFailed': 'BLE-laiteyhteyden luominen epäonnistui',

88
lib/core/translations/language/fr_fr.dart

@ -139,7 +139,8 @@ const Map<String, String> frFR = {
"bluetoothInitializationFailure":
"Échec de l'initialisation du service Bluetooth",
"checkingPermissions": "Vérification des autorisations...",
"lackPermissions": "Autorisations Bluetooth requises",
"lackPermissions":
"Autorisations Bluetooth requises et accès à la localisation nécessaire",
"searchingDevice": "Recherche d'appareils...",
"findConnectedDevice": "Appareil connecté trouvé",
"notFound": "Aucun appareil Bluetooth connecté trouvé",
@ -186,23 +187,9 @@ const Map<String, String> frFR = {
"conferenceAssistant": "Assistant de réunion d'affaires",
"conferenceAssistantInfo":
"Enregistrement de procès-verbaux en temps réel et traduction multilingue",
"studyAssistant": "Assistant d'apprentissage des langues",
"studyAssistantInfo":
"Correction de prononciation et pratique de l'expression orale",
"travelTranslator": "Traducteur de voyage",
"travelTranslatorInfo":
"Traduction vocale en temps réel et guides d'attractions",
"beSearching": "Recherche de :",
"noAssistantFound": "Aucun assistant IA correspondant trouvé",
"usageStats": "Statistiques d'utilisation",
"usageStatsInfo": "Consultez les statistiques d'utilisation de l'application",
"scene": "Scénarios",
"youHaveSelected": "Vous avez sélectionné :",
"newFunction": "Nouvelles fonctions",
"youChoseTry": "Vous avez choisi d'essayer",
"aiSinger": "Mode chanteur IA",
"aiSingerInfo":
"Chantez n'importe quelle chanson avec la voix de votre artiste préféré, même vos propres créations",
"popularFunction": "Fonctions populaires",
"tryNow": "Essayer maintenant",
// 商务会议助手页
"startMeeting": "Démarrer la réunion",
@ -218,8 +205,12 @@ const Map<String, String> frFR = {
'meetingTranscript': 'Transcription de la réunion',
// 设置页
"systemSettings": "Paramètres système",
"premiumMember": "Membre premium",
"systemSettings": "Paramètres système", //系统设置
"vipRecharge": "Recharge de VIP", //会员充值
"aiRecharge": "Membre premium", //AI充值
"translationRecharge": "Recharge de traduction", //翻译充值
"meetingAssistantRecharge": "Recharge de l'assistant de réunion", //会议助手充值
"cloudSync": "Recharge de synchronisation cloud", //云端同步
"joinDevice": "Appareil connecté :",
"accountId": "ID du compte :",
"systemSetting": "Paramètres système",
@ -292,7 +283,7 @@ const Map<String, String> frFR = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Effacer l'historique de chat",
"online": "En ligne",
"inputMessage": "Saisir un message...",
@ -320,14 +311,13 @@ const Map<String, String> frFR = {
"swipeUpForMore": "Glisser vers le haut pour plus",
// Agent controller
'welcomeMessage':
'Bonjour ! Je suis **XiaoYan**, je peux vous aider avec :\n\n'
'• Répondre aux questions et fournir des informations\n\n'
'• Traduction vocale en temps réel\n\n'
'• Recommander de la musique et des podcasts\n\n'
'• Mémos vocaux et rappels\n\n'
'• Contrôler les fonctions des écouteurs\n\n'
'Comment puis-je vous aider ?',
'welcomeMessage': 'Bonjour ! Je suis **Lily**, je peux vous aider avec :\n\n'
'• Répondre aux questions et fournir des informations\n\n'
'• Traduction vocale en temps réel\n\n'
'• Recommander de la musique et des podcasts\n\n'
'• Mémos vocaux et rappels\n\n'
'• Contrôler les fonctions des écouteurs\n\n'
'Comment puis-je vous aider ?',
'microphonePermission': 'Microphone',
'voiceRecognitionPermissionText':
'La fonction de reconnaissance vocale nécessite l\'accès au microphone.',
@ -724,7 +714,7 @@ const Map<String, String> frFR = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Appairage d'appareil",
"connectYourDeepSoundHeadset": "Connectez votre casque DeepSound",
"connectYourDeepSoundHeadset": "Connectez votre casque Voitrans",
"bind": "Lier",
"authorizeBind": "Autoriser la liaison",
"enterCode": "Veuillez saisir le code",
@ -743,7 +733,7 @@ const Map<String, String> frFR = {
"preparingPairingEnvironment":
"Préparation de l'environnement d'appairage...",
"connectDeepSoundViaSystemBluetooth":
"Veuillez d'abord connecter l'appareil DeepSound via le Bluetooth système",
"Veuillez d'abord connecter l'appareil Voitrans via le Bluetooth système",
"deviceBindingConfirm": "Confirmation de liaison d'appareil...",
"establishingDeviceAssociation":
"Établissement de l'association d'appareil...",
@ -753,7 +743,7 @@ const Map<String, String> frFR = {
// 配对错误状态文本
"ensureConnectedDeepSoundDevice":
"Veuillez vous assurer que l'appareil connecté est DeepSound",
"Veuillez vous assurer que l'appareil connecté est Voitrans",
"deviceAlreadyBoundToOtherAccount":
"Cet appareil est déjà lié à un autre compte",
"deviceAssociationFailed":
@ -788,7 +778,7 @@ const Map<String, String> frFR = {
'pleaseGrantNecessaryPermissions':
'Veuillez accorder les autorisations nécessaires',
'checkFailedRetry': 'Échec de la vérification, veuillez réessayer',
'pleaseConnectDeepSoundDevice': 'Veuillez connecter l\'appareil DeepSound',
'pleaseConnectDeepSoundDevice': 'Veuillez connecter l\'appareil Voitrans',
'verificationFailedRetry': 'Échec de la vérification, veuillez réessayer',
'invalidDeviceAddress': 'Adresse d\'appareil invalide',
'bleDeviceAssociationFailed': 'Échec de l\'association d\'appareil BLE',
@ -883,4 +873,38 @@ const Map<String, String> frFR = {
"乌尔都语": "Ourdou",
"波斯语": "Persan",
"斯瓦希里语": "Swahili",
// Guide overlay keys (placeholders in English)
"sayLilyHint": "Say \"Lily Lily\" to the mic",
"imHere": "I’m here~",
"guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Lily”.",
"aiReplyCompleted": "Lily has finished the reply!",
"aiThinking": "Lily is thinking…",
"guideAwakenSuccess": "Great! Lily is awake—ask it to help.",
"confirmInput": "Confirm Input",
"guideClickSendPrefix": "Tap send, ",
"guideWeatherStart": "Tell Lily: “What’s the weather today?”",
"guideWeatherInput": "What’s the weather today?",
"guideWeatherSend": "Lily will report the weather in real time",
"guideWeatherEnd": "Lily can report weather live—try other commands",
"guideMusicStart": "Tell Lily: “Play some rock music”",
"guideMusicInput": "Play some rock music",
"guideMusicSend": "Lily will find music for you",
"guideMusicEnd": "Lily found music—try other commands",
"guideNavStart": "Tell Lily: “Navigate to Shenzhen Airport”",
"guideNavInput": "Navigate to Shenzhen Airport",
"guideNavSend": "Lily will plan the route",
"guideNavEnd": "Navigation set—try other commands",
"guideMeetingStart":
"Tell Lily: “Create a meeting reminder for 3pm tomorrow”",
"guideMeetingInput": "Create a meeting reminder for 3pm tomorrow",
"guideMeetingSend": "Lily will create a meeting reminder",
"guideMeetingEnd": "Reminder created—try other commands",
"guidePhoneStart": "Tell Lily: “Call Mom”",
"guidePhoneInput": "Call Mom",
"guidePhoneSend": "Lily will make the call",
"guidePhoneEnd": "Call placed—try other commands",
"guideSmsStart": "Tell Lily: “Send Dad a text: I’ll be home for dinner”",
"guideSmsInput": "Text Dad: I’ll be home for dinner",
"guideSmsSend": "Lily will send the message",
"guideSmsEnd": "Message sent—voice control is convenient",
};

140
lib/core/translations/language/hi_in.dart

@ -134,7 +134,8 @@ const Map<String, String> hiIN = {
"initializing": "प्रारंभ हो रहा है...",
"bluetoothInitializationFailure": "ब्लूटूथ सेवा प्रारंभ करने में विफल",
"checkingPermissions": "अनुमतियों की जाँच हो रही है...",
"lackPermissions": "ब्लूटूथ अनुमतियों की कमी है",
"lackPermissions":
"ब्लूटूथ अनुमतियों की कमी है और लोकेशन तक पहुंच नहीं सकता है",
"searchingDevice": "डिवाइस खोज रहा है...",
"findConnectedDevice": "कनेक्टेड डिवाइस मिला",
"notFound": "कोई कनेक्टेड ब्लूटूथ डिवाइस नहीं मिला",
@ -179,21 +180,9 @@ const Map<String, String> hiIN = {
"conferenceAssistant": "बिजनेस मीटिंग असिस्टेंट",
"conferenceAssistantInfo":
"रीयल-टाइम मीटिंग मिनट रिकॉर्डिंग, बहु-भाषा अनुवाद",
"studyAssistant": "भाषा सीखने का सहायक",
"studyAssistantInfo": "उच्चारण सुधार, रीयल-टाइम बोलने का अभ्यास",
"travelTranslator": "यात्रा अनुवाद सहायक",
"travelTranslatorInfo": "रीयल-टाइम वॉयस अनुवाद, पर्यटन स्थलों का परिचय",
"beSearching": "खोज रहा है:",
"noAssistantFound": "कोई संबंधित एआई सहायक नहीं मिला",
"usageStats": "उपयोग सtatistik",
"usageStatsInfo": "अप्लिकेशन का उपयोग सtatistik देखें",
"scene": "दृश्य",
"youHaveSelected": "आपने चुना है:",
"newFunction": "नया फ़ंक्शन",
"youChoseTry": "आपने कोशिश करने के लिए चुना",
"aiSinger": "एआई सिंगर मोड",
"aiSingerInfo":
"अपने पसंदीदा गायक की आवाज में कोई भी गाना गाएं, यहां तक कि अपनी खुद की रचनाएं भी",
"popularFunction": "लोकप्रिय फ़ंक्शन दृश्य",
"tryNow": "अभी চেষ্টা করুন",
// 商务会议助手页
"startMeeting": "बैठक शुरू करें",
@ -209,8 +198,12 @@ const Map<String, String> hiIN = {
'meetingTranscript': 'बैठक का प्रतिलेख',
// 设置页
"systemSettings": "सिस्टम सेटिंग्स",
"premiumMember": "प्रीमियम सदस्य",
"systemSettings": "सिस्टम सेटिंग्स", //系统设置
"vipRecharge": "प्रीमियम सदस्य रिचार्ज", //会员充值
"aiRecharge": "प्रीमियम सदस्य", //AI充值
"translationRecharge": "अनुवाद रिचार्ज", //翻译充值
"meetingAssistantRecharge": "बैठक असिस्टेंट रिचार्ज", //会议助手充值
"cloudSync": "क्लाउड सिंक्रोनाइज़ेशन रिचार्ज", //云端同步
"joinDevice": "कनेक्टेड डिवाइस:",
"accountId": "खाता आईडी:",
"systemSetting": "सिस्टम सेटिंग",
@ -279,7 +272,7 @@ const Map<String, String> hiIN = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "चैट इतिहास साफ़ करें",
"online": "ऑनलाइन",
"inputMessage": "संदेश दर्ज करें...",
@ -307,7 +300,7 @@ const Map<String, String> hiIN = {
"swipeUpForMore": "अधिक के लिए ऊपर स्वाइप करें",
// Agent controller
'welcomeMessage': 'नमस्ते! मैं **XiaoYan** हूँ, मैं आपकी मदद कर सकता हूँ:\n\n'
'welcomeMessage': 'नमस्ते! मैं **Lily** हूँ, मैं आपकी मदद कर सकता हूँ:\n\n'
'• सवालों के जवाब देना और जानकारी प्रदान करना\n\n'
'• रीयल-टाइम वॉयस अनुवाद\n\n'
'• संगीत और पॉडकास्ट की सिफारिश करना\n\n'
@ -698,7 +691,7 @@ const Map<String, String> hiIN = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "डिवाइस पेयरिंग",
"connectYourDeepSoundHeadset": "अपना DeepSound हेडसेट कनेक्ट करें",
"connectYourDeepSoundHeadset": "अपना Voitrans हेडसेट कनेक्ट करें",
"bind": "बाँधें",
"authorizeBind": "बाँधने को अधिकृत करें",
"enterCode": "कृपया कोड दर्ज करें",
@ -753,7 +746,7 @@ const Map<String, String> hiIN = {
'retryAuthorization': 'प्राधिकरण पुनः प्रयास करें',
'pleaseGrantNecessaryPermissions': 'कृपया आवश्यक अनुमतियाँ दें',
'checkFailedRetry': 'जाँच विफल, कृपया पुनः प्रयास करें',
'pleaseConnectDeepSoundDevice': 'कृपया एक DeepSound डिवाइस कनेक्ट करें',
'pleaseConnectDeepSoundDevice': 'कृपया एक Voitrans डिवाइस कनेक्ट करें',
'verificationFailedRetry': 'सत्यापन विफल, कृपया पुनः प्रयास करें',
'invalidDeviceAddress': 'अमान्य डिवाइस पता',
'bleDeviceAssociationFailed': 'BLE डिवाइस एसोसिएशन विफल',
@ -848,4 +841,109 @@ const Map<String, String> hiIN = {
"乌尔都语": "उर्दू",
"波斯语": "फारसी",
"斯瓦希里语": "स्वाहिली",
// Guide overlay keys (placeholders in English)
"sayLilyHint": "Say \"Lily Lily\" to the mic",
"imHere": "I’m here~",
"guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Lily”.",
"aiReplyCompleted": "Lily has finished the reply!",
"aiThinking": "Lily is thinking…",
"guideAwakenSuccess": "Great! Lily is awake—ask it to help.",
"confirmInput": "Confirm Input",
"guideClickSendPrefix": "Tap send, ",
"guideWeatherStart": "Tell Lily: “What’s the weather today?”",
"guideWeatherInput": "What’s the weather today?",
"guideWeatherSend": "Lily will report the weather in real time",
"guideWeatherEnd": "Lily can report weather live—try other commands",
"guideMusicStart": "Tell Lily: “Play some rock music”",
"guideMusicInput": "Play some rock music",
"guideMusicSend": "Lily will find music for you",
"guideMusicEnd": "Lily found music—try other commands",
"guideNavStart": "Tell Lily: “Navigate to Shenzhen Airport”",
"guideNavInput": "Navigate to Shenzhen Airport",
"guideNavSend": "Lily will plan the route",
"guideNavEnd": "Navigation set—try other commands",
"guideMeetingStart":
"Tell Lily: “Create a meeting reminder for 3pm tomorrow”",
"guideMeetingInput": "Create a meeting reminder for 3pm tomorrow",
"guideMeetingSend": "Lily will create a meeting reminder",
"guideMeetingEnd": "Reminder created—try other commands",
"guidePhoneStart": "Tell Lily: “Call Mom”",
"guidePhoneInput": "Call Mom",
"guidePhoneSend": "Lily will make the call",
"guidePhoneEnd": "Call placed—try other commands",
"guideSmsStart": "Tell Lily: “Send Dad a text: I’ll be home for dinner”",
"guideSmsInput": "Text Dad: I’ll be home for dinner",
"guideSmsSend": "Lily will send the message",
"guideSmsEnd": "Message sent—voice control is convenient",
// Goods pages common footer (placeholders)
'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans',
'copyrightVoitrans': '© 2025 Voitrans Technologies',
// Meeting goods page (placeholders)
'meetingHeaderDesc1':
'Audio recording, transcription, keyword search, and auto summary.',
'meetingHeaderDesc2':
'Suitable for business meetings, class notes, and interview minutes.',
'meetingAutoRecording': 'Auto recording and segmentation',
'meetingSpeakerTagging': 'Speaker labeling',
'meetingLongAudioTranscription': 'Long audio transcription',
'meetingKeyPointSummary': 'Key point extraction',
'meetingTopicNameSearch': 'Search by topic/name',
'meetingTimelineJump': 'Timeline jump',
'meetingExportSummary': 'Export minutes',
'meetingMultiPlatformShare': 'Share across platforms',
'meetingDisclaimer':
'Use in quiet environments; performance depends on microphone and network.',
// Translation goods page (placeholders)
'transHeaderDesc1':
'रीयल-टाइम समकालीन व्याख्या और पाठ अनुवाद, कम विलंबता वॉइस प्रसारण के साथ।',
'transHeaderDesc2': 'यात्रा, व्यवसाय, भाषण और शिक्षण के लिए उपयुक्त।',
'translateZhEn': 'चीनी-अंग्रेज़ी अनुवाद',
'lowLatencyVoiceBroadcast': 'कम विलंबता वॉइस प्रसारण',
'multiLangTextTranslation': 'बहुभाषी पाठ अनुवाद',
'termOptimizationContextPreserve':
'पारिभाषिक शब्दों का अनुकूलन और संदर्भ बनाए रखना',
'lexiconTourBusinessLife': 'यात्रा/व्यवसाय/जीवन शब्दकोश',
'personalVocabularyMemory': 'व्यक्तिगत शब्दावली स्मृति',
'conversationSubtitleLargeText': 'वार्तालाप उपशीर्षक / बड़े-टेक्स्ट मोड',
'colorHighContrast': 'उच्च रंग-विपरीत',
'transDisclaimer':
'अनुवाद की गुणवत्ता माइक्रोफोन, नेटवर्क विलंबता और परिवेशी शोर पर निर्भर करती है।',
// VIP goods page (placeholders)
'benefitsOverview': 'लाभों का अवलोकन',
'higherQuota': 'उच्च उपयोग कोटा',
'lowerUnitPrice': 'कम इकाई मूल्य',
'priorityService': 'प्राथमिकता सेवा',
'exclusiveSupportChannel': 'समर्पित सहायता चैनल',
'fastResponse': 'समस्याओं पर तेज़ प्रतिक्रिया',
'eventsAndDiscounts': 'इवेंट और छूट',
'memberExclusiveEvents': 'सदस्य-विशेष इवेंट',
'longTermDiscountPlan': 'दीर्घकालीन छूट योजना',
'generalPrivileges': 'सामान्य विशेषाधिकार',
'earlyAccessNewFeatures': 'नई सुविधाओं का प्रारंभिक उपयोग',
'crossDeviceSync': 'क्रॉस-डिवाइस सिंक',
'vipDisclaimer':
'वास्तविक लाभ पैकेज विवरण पर निर्भर करते हैं और संस्करणों के साथ बदल सकते हैं।',
// Goods names by id
'ai_001_name': 'एआई बेसिक 100',
'ai_002_name': 'एआई बेसिक 500',
'ai_003_name': 'एआई बेसिक 1000',
'meet_001_name': 'मीटिंग बेसिक 100',
'meet_002_name': 'मीटिंग बेसिक 500',
'meet_003_name': 'मीटिंग बेसिक 1000',
'trans_001_name': 'अनुवाद बेसिक 100',
'trans_002_name': 'अनुवाद बेसिक 500',
'trans_003_name': 'अनुवाद बेसिक 1000',
// Goods descriptions by id
'ai_001_desc': '100 उपयोग शामिल। मुख्य AI सुविधाओं की पहुँच।',
'ai_002_desc': '500 उपयोग शामिल। मुख्य AI सुविधाओं की पहुँच।',
'ai_003_desc': '1000 उपयोग शामिल। मुख्य AI सुविधाओं की पहुँच।',
'meet_001_desc': '100 बैठक रिकॉर्डिंग/ट्रांसक्रिप्शन शामिल।',
'meet_002_desc': '500 बैठक रिकॉर्डिंग/ट्रांसक्रिप्शन शामिल।',
'meet_003_desc': '1000 बैठक रिकॉर्डिंग/ट्रांसक्रिप्शन शामिल।',
'trans_001_desc': '100 अनुवाद (वॉयस/टेक्स्ट) शामिल।',
'trans_002_desc': '500 अनुवाद (वॉयस/टेक्स्ट) शामिल।',
'trans_003_desc': '1000 अनुवाद (वॉयस/टेक्स्ट) शामिल।',
};

35
lib/core/translations/language/hr_hr.dart

@ -137,7 +137,8 @@ const Map<String, String> hrHR = {
"bluetoothInitializationFailure":
"Inicijalizacija Bluetooth usluge nije uspjela",
"checkingPermissions": "Provjera dopuštenja...",
"lackPermissions": "Nedostaju Bluetooth dopuštenja",
"lackPermissions":
"Nedostaju Bluetooth dopuštenja i pristup lokacijskom podacima je potrebno",
"searchingDevice": "Pretraživanje uređaja...",
"findConnectedDevice": "Pronađen povezan uređaj",
"notFound": "Nije pronađen povezan Bluetooth uređaj",
@ -183,23 +184,9 @@ const Map<String, String> hrHR = {
"conferenceAssistant": "Asistent za poslovne sastanke",
"conferenceAssistantInfo":
"Bilježenje zapisnika u stvarnom vremenu, višejezični prijevod",
"studyAssistant": "Asistent za učenje jezika",
"studyAssistantInfo":
"Ispravak izgovora, vježbanje govora u stvarnom vremenu",
"travelTranslator": "Asistent za prevođenje na putovanjima",
"travelTranslatorInfo":
"Glasovni prijevod u stvarnom vremenu, predstavljanje turističkih atrakcija",
"beSearching": "Traženje:",
"noAssistantFound": "Nije pronađen odgovarajući AI asistent",
"usageStats": "Statistika upotrebe",
"usageStatsInfo": "Pregledajte statistiku upotrebe aplikacije",
"scene": "Scenarij",
"youHaveSelected": "Odabrali ste:",
"newFunction": "Nova funkcija",
"youChoseTry": "Odabrali ste isprobati",
"aiSinger": "AI pjevač način rada",
"aiSingerInfo":
"Pjevajte bilo koju pjesmu glasom svog omiljenog pjevača, čak i vlastite skladbe",
"popularFunction": "Popularni scenariji funkcija",
"tryNow": "Isprobaj sada",
// 商务会议助手页
"startMeeting": "Započni sastanak",
@ -215,8 +202,12 @@ const Map<String, String> hrHR = {
'meetingTranscript': 'Transkript sastanka',
// 设置页
"systemSettings": "Postavke sustava",
"premiumMember": "Premium član",
"systemSettings": "Postavke sustava", //系统设置
"vipRecharge": "Ponuda premium članstva", //会员充值
"aiRecharge": "Premium član", //AI充值
"translationRecharge": "Prijevod ponuda", //翻译充值
"meetingAssistantRecharge": "Asistent sastanka ponuda", //会议助手充值
"cloudSync": "Synchronizacija u oblaku ponuda", //云端同步
"joinDevice": "Povezan uređaj:",
"accountId": "ID računa:",
"systemSetting": "Postavke sustava",
@ -285,7 +276,7 @@ const Map<String, String> hrHR = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Obriši povijest razgovora",
"online": "Na mreži",
"inputMessage": "Unesite poruku...",
@ -312,7 +303,7 @@ const Map<String, String> hrHR = {
"swipeUpForMore": "Prijeđite prstom prema gore za više",
// Agent controller
'welcomeMessage': 'Zdravo! Ja sam **XiaoYan**, mogu vam pomoći:\n\n'
'welcomeMessage': 'Zdravo! Ja sam **Lily**, mogu vam pomoći:\n\n'
'• Odgovarati na pitanja i pružati informacije\n\n'
'• Glasovno prevođenje u stvarnom vremenu\n\n'
'• Preporučivati glazbu i podcaste\n\n'
@ -702,7 +693,7 @@ const Map<String, String> hrHR = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Uparivanje uređaja",
"connectYourDeepSoundHeadset": "Povežite svoje DeepSound slušalice",
"connectYourDeepSoundHeadset": "Povežite svoje Voitrans slušalice",
"bind": "Poveži",
"authorizeBind": "Autoriziraj povezivanje",
"enterCode": "Unesite kod",

36
lib/core/translations/language/hu_hu.dart

@ -139,7 +139,8 @@ const Map<String, String> huHU = {
"bluetoothInitializationFailure":
"A Bluetooth szolgáltatás inicializálása sikertelen",
"checkingPermissions": "Engedélyek ellenőrzése...",
"lackPermissions": "Hiányoznak a Bluetooth engedélyek",
"lackPermissions":
"Hiányoznak a Bluetooth engedélyek és a helyzetek elérése szükséges",
"searchingDevice": "Eszközök keresése...",
"findConnectedDevice": "Csatlakoztatott eszköz található",
"notFound": "Nem található csatlakoztatott Bluetooth eszköz",
@ -184,22 +185,9 @@ const Map<String, String> huHU = {
"healthConsultantInfo": "További AI csevegési funkciókat kínál",
"conferenceAssistant": "Üzleti megbeszélés asszisztens",
"conferenceAssistantInfo": "Valós idejű jegyzőkönyvezés, többnyelvű fordítás",
"studyAssistant": "Nyelvtanulási asszisztens",
"studyAssistantInfo": "Kiejtésjavítás, valós idejű beszédgyakorlás",
"travelTranslator": "Utazási fordító asszisztens",
"travelTranslatorInfo":
"Valós idejű hangfordítás, turisztikai látványosságok bemutatása",
"beSearching": "Keresés:",
"noAssistantFound": "Nem található megfelelő AI asszisztens",
"usageStats": "Használati statisztika",
"usageStatsInfo": "Lásd a használati statisztikát",
"scene": "Helyzet",
"youHaveSelected": "Ön választotta:",
"newFunction": "Új funkció",
"youChoseTry": "Ön a próbát választotta",
"aiSinger": "AI énekes mód",
"aiSingerInfo":
"Énekeljen el bármilyen dalt kedvenc énekese hangján, akár saját szerzeményeit is",
"popularFunction": "Népszerű funkciók",
"tryNow": "Próbálja ki most",
// 商务会议助手页
"startMeeting": "Megbeszélés indítása",
@ -215,8 +203,12 @@ const Map<String, String> huHU = {
'meetingTranscript': 'Megbeszélés átirata',
// 设置页
"systemSettings": "Rendszerbeállítások",
"premiumMember": "Prémium tag",
"systemSettings": "Rendszerbeállítások", //系统设置
"vipRecharge": "Prémium tag ponuda", //会员充值
"aiRecharge": "Prémium tag", //AI充值
"translationRecharge": "Fordítás ponuda", //翻译充值
"meetingAssistantRecharge": "Megbeszélés asszisztens ponuda", //会议助手充值
"cloudSync": "Synchronizációs ponuda", //云端同步
"joinDevice": "Csatlakoztatott eszköz:",
"accountId": "Fiók azonosító:",
"systemSetting": "Rendszerbeállítás",
@ -285,7 +277,7 @@ const Map<String, String> huHU = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Csevegési előzmények törlése",
"online": "Online",
"inputMessage": "Üzenet beírása...",
@ -313,7 +305,7 @@ const Map<String, String> huHU = {
"swipeUpForMore": "Húzza felfelé a továbbiakért",
// Agent controller
'welcomeMessage': 'Szia! **XiaoYan** vagyok, segíthetek neked:\n\n'
'welcomeMessage': 'Szia! **Lily** vagyok, segíthetek neked:\n\n'
'• Kérdések megválaszolásában és információk nyújtásában\n\n'
'• Valós idejű hangfordításban\n\n'
'• Zene és podcastok ajánlásában\n\n'
@ -701,7 +693,7 @@ const Map<String, String> huHU = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Eszköz párosítása",
"connectYourDeepSoundHeadset": "Csatlakoztassa a DeepSound fülhallgatóját",
"connectYourDeepSoundHeadset": "Csatlakoztassa a Voitrans fülhallgatóját",
"bind": "Párosítás",
"authorizeBind": "Párosítás engedélyezése",
"enterCode": "Kérjük, adja meg a kódot",
@ -757,7 +749,7 @@ const Map<String, String> huHU = {
'Kérjük, adja meg a szükséges engedélyeket',
'checkFailedRetry': 'Az ellenőrzés sikertelen, próbálja újra',
'pleaseConnectDeepSoundDevice':
'Kérjük, csatlakoztasson egy DeepSound eszközt',
'Kérjük, csatlakoztasson egy Voitrans eszközt',
'verificationFailedRetry': 'Az ellenőrzés sikertelen, próbálja újra',
'invalidDeviceAddress': 'Érvénytelen eszközcím',
'bleDeviceAssociationFailed': 'A BLE eszköztársítás sikertelen',

35
lib/core/translations/language/id_id.dart

@ -135,7 +135,7 @@ const Map<String, String> idID = {
"initializing": "Menginisialisasi...",
"bluetoothInitializationFailure": "Inisialisasi layanan Bluetooth gagal",
"checkingPermissions": "Memeriksa izin...",
"lackPermissions": "Izin Bluetooth tidak ada",
"lackPermissions": "Izin Bluetooth tidak ada dan akses lokasi diperlukan",
"searchingDevice": "Mencari perangkat...",
"findConnectedDevice": "Perangkat terhubung ditemukan",
"notFound": "Tidak ada perangkat Bluetooth yang terhubung ditemukan",
@ -180,22 +180,9 @@ const Map<String, String> idID = {
"conferenceAssistant": "Asisten Rapat Bisnis",
"conferenceAssistantInfo":
"Catatan rapat waktu nyata, terjemahan multibahasa",
"studyAssistant": "Asisten Belajar Bahasa",
"studyAssistantInfo": "Koreksi pengucapan, latihan berbicara waktu nyata",
"travelTranslator": "Asisten Terjemahan Perjalanan",
"travelTranslatorInfo":
"Terjemahan suara waktu nyata, pengenalan tempat wisata",
"beSearching": "Mencari:",
"noAssistantFound": "Tidak ada asisten AI yang cocok ditemukan",
"usageStats": "Statistik Penggunaan",
"usageStatsInfo": "Lihat statistik penggunaan aplikasi",
"scene": "Skenario",
"youHaveSelected": "Anda telah memilih:",
"newFunction": "Fitur Baru",
"youChoseTry": "Anda memilih untuk mencoba",
"aiSinger": "Mode Penyanyi AI",
"aiSingerInfo":
"Nyanyikan lagu apa pun dengan suara penyanyi favorit Anda, bahkan lagu ciptaan Anda sendiri",
"popularFunction": "Skenario Fitur Populer",
"tryNow": "Coba Sekarang",
// 商务会议助手页
"startMeeting": "Mulai Rapat",
@ -211,8 +198,12 @@ const Map<String, String> idID = {
'meetingTranscript': 'Transkrip Rapat',
// 设置页
"systemSettings": "Pengaturan Sistem",
"premiumMember": "Anggota Premium",
"systemSettings": "Pengaturan Sistem", //系统设置
"vipRecharge": "Pembayaran Premium", //会员充值
"aiRecharge": "Anggota Premium", //AI充值
"translationRecharge": "Pembayaran Terjemahan", //翻译充值
"meetingAssistantRecharge": "Pembayaran Asisten Rapat", //会议助手充值
"cloudSync": "Pembayaran Sinkronisasi awan", //云端同步
"joinDevice": "Perangkat terhubung:",
"accountId": "ID Akun:",
"systemSetting": "Pengaturan Sistem",
@ -281,7 +272,7 @@ const Map<String, String> idID = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Hapus Riwayat Obrolan",
"online": "Online",
"inputMessage": "Masukkan pesan...",
@ -309,7 +300,7 @@ const Map<String, String> idID = {
"swipeUpForMore": "Geser ke atas untuk lebih banyak",
// Agent controller
'welcomeMessage': 'Halo! Saya **XiaoYan**, saya bisa membantu Anda:\n\n'
'welcomeMessage': 'Halo! Saya **Lily**, saya bisa membantu Anda:\n\n'
'• Menjawab pertanyaan dan memberikan informasi\n\n'
'• Terjemahan suara waktu nyata\n\n'
'• Merekomendasikan musik dan podcast\n\n'
@ -698,7 +689,7 @@ const Map<String, String> idID = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Pemasangan Perangkat",
"connectYourDeepSoundHeadset": "Hubungkan Headset DeepSound Anda",
"connectYourDeepSoundHeadset": "Hubungkan Headset Voitrans Anda",
"bind": "Ikat",
"authorizeBind": "Otorisasi Pengikatan",
"enterCode": "Silakan masukkan kode",
@ -752,7 +743,7 @@ const Map<String, String> idID = {
'retryAuthorization': 'Coba Ulang Otorisasi',
'pleaseGrantNecessaryPermissions': 'Harap berikan izin yang diperlukan',
'checkFailedRetry': 'Pemeriksaan gagal, silakan coba lagi',
'pleaseConnectDeepSoundDevice': 'Harap hubungkan perangkat DeepSound',
'pleaseConnectDeepSoundDevice': 'Harap hubungkan perangkat Voitrans',
'verificationFailedRetry': 'Verifikasi gagal, silakan coba lagi',
'invalidDeviceAddress': 'Alamat perangkat tidak valid',
'bleDeviceAssociationFailed': 'Asosiasi perangkat BLE gagal',

33
lib/core/translations/language/is_is.dart

@ -135,7 +135,8 @@ const Map<String, String> isIS = {
"initializing": "Frumstilli...",
"bluetoothInitializationFailure": "Frumstilling Bluetooth-þjónustu mistókst",
"checkingPermissions": "Athuga heimildir...",
"lackPermissions": "Skortir Bluetooth-heimildir",
"lackPermissions":
"Skortir Bluetooth-heimildir og lokatæknið er þó ekki tilgengilegt",
"searchingDevice": "Leita að tækjum...",
"findConnectedDevice": "Fann tengt tæki",
"notFound": "Ekkert tengt Bluetooth-tæki fannst",
@ -180,21 +181,9 @@ const Map<String, String> isIS = {
"healthConsultantInfo": "Býður upp á fleiri gervigreindarspjallaðgerðir",
"conferenceAssistant": "Aðstoðarmaður fyrir viðskiptafundi",
"conferenceAssistantInfo": "Skráning fundargerða í rauntíma, fjöltyng þýðing",
"studyAssistant": "Aðstoðarmaður við tungumálanám",
"studyAssistantInfo": "Framburðarleiðrétting, rauntímaæfing í tali",
"travelTranslator": "Aðstoðarmaður við ferðaþýðingu",
"travelTranslatorInfo": "Rauntíma raddþýðing, kynning á ferðamannastöðum",
"beSearching": "Leita:",
"noAssistantFound": "Enginn samsvarandi gervigreindar-aðstoðarmaður fannst",
"usageStats": "Notendastatistika",
"usageStatsInfo": " skoða notendastatistika",
"scene": "Atburðarás",
"youHaveSelected": "Þú valdir:",
"newFunction": "Nýr eiginleiki",
"youChoseTry": "Þú valdir að prófa",
"aiSinger": "Gervigreindarsöngvarahamur",
"aiSingerInfo":
"Syngdu hvaða lag sem er með rödd uppáhalds söngvarans þíns, jafnvel þínar eigin tónsmíðar",
"popularFunction": "Vinsælir eiginleikaatburðir",
"tryNow": "Prófa núna",
// 商务会议助手页
"startMeeting": "Hefja fund",
@ -210,8 +199,12 @@ const Map<String, String> isIS = {
'meetingTranscript': 'Fundarritun',
// 设置页
"systemSettings": "Kerfisstillingar",
"premiumMember": "Premium meðlimur",
"systemSettings": "Kerfisstillingar", //系统设置
"vipRecharge": "Premium meðlimurinnsla", //会员充值
"aiRecharge": "Premium meðlimur", //AI充值
"translationRecharge": "Þýðingsponsoring", //翻译充值
"meetingAssistantRecharge": "Fundarasistentsponsoring", //会议助手充值
"cloudSync": "Synchronisering með skýjaraddþjónustu", //云端同步
"joinDevice": "Tengt tæki:",
"accountId": "Auðkenni reiknings:",
"systemSetting": "Kerfisstillingar",
@ -280,7 +273,7 @@ const Map<String, String> isIS = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Hreinsa spjallsögu",
"online": "Á netinu",
"inputMessage": "Sláðu inn skilaboð...",
@ -307,7 +300,7 @@ const Map<String, String> isIS = {
"swipeUpForMore": "Strjúktu upp til að sjá meira",
// Agent controller
'welcomeMessage': 'Halló! Ég er **XiaoYan**, ég get hjálpað þér með:\n\n'
'welcomeMessage': 'Halló! Ég er **Lily**, ég get hjálpað þér með:\n\n'
'• Að svara spurningum og veita upplýsingar\n\n'
'• Rauntíma raddþýðingu\n\n'
'• Að mæla með tónlist og hlaðvörpum\n\n'
@ -698,7 +691,7 @@ const Map<String, String> isIS = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Pörun tækis",
"connectYourDeepSoundHeadset": "Tengdu DeepSound heyrnartólin þín",
"connectYourDeepSoundHeadset": "Tengdu Voitrans heyrnartólin þín",
"bind": "Binda",
"authorizeBind": "Heimila bindingu",
"enterCode": "Vinsamlegast sláðu inn kóðann",

131
lib/core/translations/language/it_it.dart

@ -137,7 +137,8 @@ const Map<String, String> itIT = {
"bluetoothInitializationFailure":
"Inizializzazione del servizio Bluetooth fallita",
"checkingPermissions": "Verifica autorizzazioni...",
"lackPermissions": "Mancano le autorizzazioni Bluetooth",
"lackPermissions":
"Mancano le autorizzazioni Bluetooth e l'accesso alla posizione è necessario",
"searchingDevice": "Ricerca dispositivi...",
"findConnectedDevice": "Dispositivo connesso trovato",
"notFound": "Nessun dispositivo Bluetooth connesso trovato",
@ -185,23 +186,9 @@ const Map<String, String> itIT = {
"conferenceAssistant": "Assistente per riunioni di lavoro",
"conferenceAssistantInfo":
"Registrazione di verbali in tempo reale, traduzione multilingue",
"studyAssistant": "Assistente per l'apprendimento delle lingue",
"studyAssistantInfo":
"Correzione della pronuncia, pratica della conversazione in tempo reale",
"travelTranslator": "Assistente di traduzione per viaggi",
"travelTranslatorInfo":
"Traduzione vocale in tempo reale, introduzione alle attrazioni turistiche",
"beSearching": "Ricerca in corso:",
"noAssistantFound": "Nessun assistente AI corrispondente trovato",
"usageStats": "Statistiche di utilizzo",
"usageStatsInfo": "Visualizza le statistiche di utilizzo dell'applicazione",
"scene": "Scenario",
"youHaveSelected": "Hai selezionato:",
"newFunction": "Nuova funzione",
"youChoseTry": "Hai scelto di provare",
"aiSinger": "Modalità cantante AI",
"aiSingerInfo":
"Canta qualsiasi canzone con la voce del tuo cantante preferito, anche le tue composizioni",
"popularFunction": "Scenari di funzioni popolari",
"tryNow": "Prova ora",
// 商务会议助手页
"startMeeting": "Inizia riunione",
@ -217,8 +204,12 @@ const Map<String, String> itIT = {
'meetingTranscript': 'Trascrizione riunione',
// 设置页
"systemSettings": "Impostazioni di sistema",
"premiumMember": "Membro Premium",
"systemSettings": "Impostazioni di sistema", //系统设置
"vipRecharge": "Ricarica membro Premium", //会员充值
"aiRecharge": "Membro Premium", //AI充值
"translationRecharge": "Recharge traduzione", //翻译充值
"meetingAssistantRecharge": "Recharge assistente riunione", //会议助手充值
"cloudSync": "Recharge sincronizzazione cloud", //云端同步
"joinDevice": "Dispositivo connesso:",
"accountId": "ID account:",
"systemSetting": "Impostazioni di sistema",
@ -291,7 +282,7 @@ const Map<String, String> itIT = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Cancella cronologia chat",
"online": "Online",
"inputMessage": "Inserisci messaggio...",
@ -319,7 +310,7 @@ const Map<String, String> itIT = {
"swipeUpForMore": "Scorri verso l'alto per vedere di più",
// Agent controller
'welcomeMessage': 'Ciao! Sono **XiaoYan**, posso aiutarti a:\n\n'
'welcomeMessage': 'Ciao! Sono **Lily**, posso aiutarti a:\n\n'
'• Rispondere a domande e fornire informazioni\n\n'
'• Traduzione vocale in tempo reale\n\n'
'• Consigliare musica e podcast\n\n'
@ -717,7 +708,7 @@ const Map<String, String> itIT = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Associazione dispositivo",
"connectYourDeepSoundHeadset": "Connetti le tue cuffie DeepSound",
"connectYourDeepSoundHeadset": "Connetti le tue cuffie Voitrans",
"bind": "Associa",
"authorizeBind": "Autorizza associazione",
"enterCode": "Inserisci il codice",
@ -774,7 +765,7 @@ const Map<String, String> itIT = {
'retryAuthorization': 'Riprova autorizzazione',
'pleaseGrantNecessaryPermissions': 'Concedi le autorizzazioni necessarie',
'checkFailedRetry': 'Controllo fallito, riprova',
'pleaseConnectDeepSoundDevice': 'Connetti un dispositivo DeepSound',
'pleaseConnectDeepSoundDevice': 'Connetti un dispositivo Voitrans',
'verificationFailedRetry': 'Verifica fallita, riprova',
'invalidDeviceAddress': 'Indirizzo del dispositivo non valido',
'bleDeviceAssociationFailed': 'Associazione del dispositivo BLE fallita',
@ -869,4 +860,98 @@ const Map<String, String> itIT = {
"乌尔都语": "Urdu",
"波斯语": "Persiano",
"斯瓦希里语": "Swahili",
// Guide overlay keys (placeholders in English)
"sayLilyHint": "Say \"Lily Lily\" to the mic",
"imHere": "I’m here~",
"guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Lily”.",
"aiReplyCompleted": "Lily has finished the reply!",
"aiThinking": "Lily is thinking…",
"guideAwakenSuccess": "Great! Lily is awake—ask it to help.",
"confirmInput": "Confirm Input",
"guideClickSendPrefix": "Tap send, ",
"guideWeatherStart": "Tell Lily: “What’s the weather today?”",
"guideWeatherInput": "What’s the weather today?",
"guideWeatherSend": "Lily will report the weather in real time",
"guideWeatherEnd": "Lily can report weather live—try other commands",
"guideMusicStart": "Tell Lily: “Play some rock music”",
"guideMusicInput": "Play some rock music",
"guideMusicSend": "Lily will find music for you",
"guideMusicEnd": "Lily found music—try other commands",
"guideNavStart": "Tell Lily: “Navigate to Shenzhen Airport”",
"guideNavInput": "Navigate to Shenzhen Airport",
"guideNavSend": "Lily will plan the route",
"guideNavEnd": "Navigation set—try other commands",
"guideMeetingStart":
"Tell Lily: “Create a meeting reminder for 3pm tomorrow”",
"guideMeetingInput": "Create a meeting reminder for 3pm tomorrow",
"guideMeetingSend": "Lily will create a meeting reminder",
"guideMeetingEnd": "Reminder created—try other commands",
"guidePhoneStart": "Tell Lily: “Call Mom”",
"guidePhoneInput": "Call Mom",
"guidePhoneSend": "Lily will make the call",
"guidePhoneEnd": "Call placed—try other commands",
"guideSmsStart": "Tell Lily: “Send Dad a text: I’ll be home for dinner”",
"guideSmsInput": "Text Dad: I’ll be home for dinner",
"guideSmsSend": "Lily will send the message",
"guideSmsEnd": "Message sent—voice control is convenient",
// Goods pages common footer (placeholders)
'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans',
'copyrightVoitrans': '© 2025 Voitrans Technologies',
// Meeting goods page (placeholders)
'meetingHeaderDesc1':
'Audio recording, transcription, keyword search, and auto summary.',
'meetingHeaderDesc2':
'Suitable for business meetings, class notes, and interview minutes.',
'meetingAutoRecording': 'Auto recording and segmentation',
'meetingSpeakerTagging': 'Speaker labeling',
'meetingLongAudioTranscription': 'Long audio transcription',
'meetingKeyPointSummary': 'Key point extraction',
'meetingTopicNameSearch': 'Search by topic/name',
'meetingTimelineJump': 'Timeline jump',
'meetingExportSummary': 'Export minutes',
'meetingMultiPlatformShare': 'Share across platforms',
'meetingDisclaimer':
'Use in quiet environments; performance depends on microphone and network.',
// Translation goods page (placeholders)
'transHeaderDesc1':
'Interpretazione simultanea e traduzione di testo in tempo reale, con voce a bassa latenza.',
'transHeaderDesc2': 'Adatto a viaggi, affari, discorsi e insegnamento.',
'translateZhEn': 'Traduzione Cinese-Inglese',
'lowLatencyVoiceBroadcast': 'Trasmissione vocale a bassa latenza',
'multiLangTextTranslation': 'Traduzione di testo multilingue',
'termOptimizationContextPreserve':
'Ottimizzazione della terminologia e mantenimento del contesto',
'lexiconTourBusinessLife': 'Lessici per viaggio/affari/vita quotidiana',
'personalVocabularyMemory': 'Memoria del vocabolario personale',
'conversationSubtitleLargeText':
'Sottotitoli conversazione / modalità testo grande',
'colorHighContrast': 'Elevato contrasto dei colori',
'transDisclaimer':
'Le prestazioni della traduzione dipendono dal microfono, dalla latenza di rete e dal rumore ambientale.',
'trans_001_name': 'Traduzione Base 100',
'trans_002_name': 'Traduzione Base 500',
'trans_003_name': 'Traduzione Base 1000',
'trans_001_desc': 'Include 100 traduzioni (voce/testo).',
'trans_002_desc': 'Include 500 traduzioni (voce/testo).',
'trans_003_desc': 'Include 1000 traduzioni (voce/testo).',
// VIP goods page (placeholders)
'benefitsOverview': 'Panoramica dei vantaggi',
'higherQuota': 'Quota di utilizzo più alta',
'lowerUnitPrice': 'Prezzo unitario più basso',
'priorityService': 'Servizio prioritario',
'exclusiveSupportChannel': 'Canale di supporto dedicato',
'fastResponse': 'Risposta rapida ai problemi',
'eventsAndDiscounts': 'Eventi e sconti',
'memberExclusiveEvents': 'Eventi esclusivi per i membri',
'longTermDiscountPlan': 'Piano di sconti a lungo termine',
'generalPrivileges': 'Privilegi generali',
'earlyAccessNewFeatures': 'Accesso anticipato alle nuove funzionalità',
'crossDeviceSync': 'Sincronizzazione tra dispositivi',
'vipDisclaimer':
'I benefici effettivi dipendono dai dettagli del pacchetto e possono cambiare con le versioni.',
};

65
lib/core/translations/language/ja_jp.dart

@ -132,7 +132,7 @@ const Map<String, String> jaJP = {
"initializing": "初期化中...",
"bluetoothInitializationFailure": "Bluetoothサービスの初期化に失敗",
"checkingPermissions": "権限を確認中...",
"lackPermissions": "Bluetooth権限が必要",
"lackPermissions": "Bluetooth権限が必要です。位置情報のアクセスも必要です",
"searchingDevice": "デバイスを検索中...",
"findConnectedDevice": "接続されたデバイスが見つかりました",
"notFound": "接続されたBluetoothデバイスが見つかりません",
@ -176,20 +176,9 @@ const Map<String, String> jaJP = {
"healthConsultantInfo": "より多くのAIチャット機能",
"conferenceAssistant": "ビジネス会議アシスタント",
"conferenceAssistantInfo": "リアルタイム議事録記録と多言語翻訳",
"studyAssistant": "語学学習アシスタント",
"studyAssistantInfo": "発音矯正とスピーキング練習",
"travelTranslator": "旅行翻訳者",
"travelTranslatorInfo": "リアルタイム音声翻訳と観光地ガイド",
"beSearching": "検索中:",
"noAssistantFound": "対応するAIアシスタントが見つかりません",
"usageStats": "使用統計",
"usageStatsInfo": "使用統計を確認",
"scene": "シナリオ",
"youHaveSelected": "選択しました:",
"newFunction": "新機能",
"youChoseTry": "試すことを選択しました",
"aiSinger": "AIシンガーモード",
"aiSingerInfo": "お気に入りのアーティストの声で任意の曲を歌う、自分の創作も可能",
"popularFunction": "人気機能",
"tryNow": "今すぐ試す",
// 商务会议助手页
"startMeeting": "会議を開始",
@ -202,11 +191,15 @@ const Map<String, String> jaJP = {
'meeting': '会議',
'recordingDetails': '録音詳細',
'aiSummary': 'AI要約',
'meetingTranscript': '会議記録',
'meetingTranscript': '会議記録', //会议记录
// 设置页
"systemSettings": "システム設定",
"premiumMember": "プレミアムメンバー",
"systemSettings": "システム設定", //系统设置
"vipRecharge": "プレミアムメンバー料金", //会员充值
"aiRecharge": "プレミアムメンバー", //AI充值
"translationRecharge": "翻訳料金", //翻译充值
"meetingAssistantRecharge": "会議アシスタント料金", //会议助手充值
"cloudSync": "クラウド同期料金", //云端同步
"joinDevice": "接続デバイス:",
"accountId": "アカウントID:",
"systemSetting": "システム設定",
@ -271,7 +264,7 @@ const Map<String, String> jaJP = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "チャット履歴をクリア",
"online": "オンライン",
"inputMessage": "メッセージを入力...",
@ -298,7 +291,7 @@ const Map<String, String> jaJP = {
"swipeUpForMore": "上にスワイプしてさらに表示",
// Agent controller
'welcomeMessage': 'こんにちは!私は**XiaoYan**です。以下のことでお手伝いできます:\n\n'
'welcomeMessage': 'こんにちは!私は**Lily**です。以下のことでお手伝いできます:\n\n'
'• 質問への回答と情報提供\n\n'
'• リアルタイム音声翻訳\n\n'
'• 音楽とポッドキャストの推薦\n\n'
@ -797,4 +790,38 @@ const Map<String, String> jaJP = {
"乌尔都语": "ウルドゥー語",
"波斯语": "ペルシャ語",
"斯瓦希里语": "スワヒリ語",
// Guide overlay keys (placeholders in English)
"sayLilyHint": "Say \"Lily Lily\" to the mic",
"imHere": "I’m here~",
"guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Lily”.",
"aiReplyCompleted": "Lily has finished the reply!",
"aiThinking": "Lily is thinking…",
"guideAwakenSuccess": "Great! Lily is awake—ask it to help.",
"confirmInput": "Confirm Input",
"guideClickSendPrefix": "Tap send, ",
"guideWeatherStart": "Tell Lily: “What’s the weather today?”",
"guideWeatherInput": "What’s the weather today?",
"guideWeatherSend": "Lily will report the weather in real time",
"guideWeatherEnd": "Lily can report weather live—try other commands",
"guideMusicStart": "Tell Lily: “Play some rock music”",
"guideMusicInput": "Play some rock music",
"guideMusicSend": "Lily will find music for you",
"guideMusicEnd": "Lily found music—try other commands",
"guideNavStart": "Tell Lily: “Navigate to Shenzhen Airport”",
"guideNavInput": "Navigate to Shenzhen Airport",
"guideNavSend": "Lily will plan the route",
"guideNavEnd": "Navigation set—try other commands",
"guideMeetingStart":
"Tell Lily: “Create a meeting reminder for 3pm tomorrow”",
"guideMeetingInput": "Create a meeting reminder for 3pm tomorrow",
"guideMeetingSend": "Lily will create a meeting reminder",
"guideMeetingEnd": "Reminder created—try other commands",
"guidePhoneStart": "Tell Lily: “Call Mom”",
"guidePhoneInput": "Call Mom",
"guidePhoneSend": "Lily will make the call",
"guidePhoneEnd": "Call placed—try other commands",
"guideSmsStart": "Tell Lily: “Send Dad a text: I’ll be home for dinner”",
"guideSmsInput": "Text Dad: I’ll be home for dinner",
"guideSmsSend": "Lily will send the message",
"guideSmsEnd": "Message sent—voice control is convenient",
};

120
lib/core/translations/language/ko_kr.dart

@ -130,7 +130,7 @@ const Map<String, String> koKR = {
"initializing": "초기화 중...",
"bluetoothInitializationFailure": "블루투스 서비스 초기화 실패",
"checkingPermissions": "권한 확인 중...",
"lackPermissions": "블루투스 권한이 없습니다",
"lackPermissions": "블루투스 권한이 없습니다. 위치 정보 접근도 필요합니다",
"searchingDevice": "기기 검색 중...",
"findConnectedDevice": "연결된 기기를 찾았습니다",
"notFound": "연결된 블루투스 기기를 찾을 수 없습니다",
@ -174,20 +174,9 @@ const Map<String, String> koKR = {
"healthConsultantInfo": "더 많은 AI 채팅 기능 제공",
"conferenceAssistant": "비즈니스 회의 어시스턴트",
"conferenceAssistantInfo": "실시간 회의록 작성, 다국어 번역",
"studyAssistant": "언어 학습 어시스턴트",
"studyAssistantInfo": "발음 교정, 실시간 회화 연습",
"travelTranslator": "여행 번역 어시스턴트",
"travelTranslatorInfo": "실시간 음성 번역, 관광지 소개",
"beSearching": "검색 중:",
"noAssistantFound": "해당하는 AI 어시스턴트를 찾을 수 없습니다",
"usageStats": "사용 통계",
"usageStatsInfo": "사용 통계를 확인하세요",
"scene": "상황",
"youHaveSelected": "선택하셨습니다:",
"newFunction": "새로운 기능",
"youChoseTry": "시도하기로 선택하셨습니다",
"aiSinger": "AI 가수 모드",
"aiSingerInfo": "좋아하는 가수의 목소리로 어떤 노래든 부르세요, 심지어 직접 만든 노래까지",
"popularFunction": "인기 기능 상황",
"tryNow": "지금 시도하기",
// 商务会议助手页
"startMeeting": "회의 시작",
@ -203,8 +192,12 @@ const Map<String, String> koKR = {
'meetingTranscript': '회의 원문',
// 设置页
"systemSettings": "시스템 설정",
"premiumMember": "프리미엄 회원",
"systemSettings": "시스템 설정", //系统设置
"vipRecharge": "프리미엄 회원료", //会员充值
"aiRecharge": "프리미엄 회원", //AI充值
"translationRecharge": "번역료", //翻译充值
"meetingAssistantRecharge": "회의 어시스턴트료", //会议助手充值
"cloudSync": "클라우드 동기화료", //云端同步
"joinDevice": "연결된 기기:",
"accountId": "계정 ID:",
"systemSetting": "시스템 설정",
@ -269,7 +262,7 @@ const Map<String, String> koKR = {
//Agent 模块
// agent View
"XiaoYan": "샤오옌",
"Lily": "Lily",
"clearChatHistory": "채팅 기록 지우기",
"online": "온라인",
"inputMessage": "메시지 입력...",
@ -649,7 +642,7 @@ const Map<String, String> koKR = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "기기 페어링",
"connectYourDeepSoundHeadset": "DeepSound 헤드셋 연결",
"connectYourDeepSoundHeadset": "Voitrans 헤드셋 연결",
"bind": "연결",
"authorizeBind": "연결 승인",
"enterCode": "코드를 입력하세요",
@ -696,7 +689,7 @@ const Map<String, String> koKR = {
'retryAuthorization': '인증 재시도',
'pleaseGrantNecessaryPermissions': '필요한 권한을 부여해주세요',
'checkFailedRetry': '확인 실패, 다시 시도하세요',
'pleaseConnectDeepSoundDevice': 'DeepSound 기기를 연결해주세요',
'pleaseConnectDeepSoundDevice': 'Voitrans 기기를 연결해주세요',
'verificationFailedRetry': '인증 실패, 다시 시도하세요',
'invalidDeviceAddress': '잘못된 기기 주소',
'bleDeviceAssociationFailed': 'BLE 기기 연결 실패',
@ -784,4 +777,93 @@ const Map<String, String> koKR = {
"乌尔都语": "우르두어",
"波斯语": "페르시아어",
"斯瓦希里语": "스와힐리어",
// Guide overlay keys (placeholders in English)
"sayLilyHint": "Say \"Lily Lily\" to the mic",
"imHere": "I’m here~",
"guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Lily”.",
"aiReplyCompleted": "Lily has finished the reply!",
"aiThinking": "Lily is thinking…",
"guideAwakenSuccess": "Great! Lily is awake—ask it to help.",
"confirmInput": "Confirm Input",
"guideClickSendPrefix": "Tap send, ",
"guideWeatherStart": "Tell Lily: “What’s the weather today?”",
"guideWeatherInput": "What’s the weather today?",
"guideWeatherSend": "Lily will report the weather in real time",
"guideWeatherEnd": "Lily can report weather live—try other commands",
"guideMusicStart": "Tell Lily: “Play some rock music”",
"guideMusicInput": "Play some rock music",
"guideMusicSend": "Lily will find music for you",
"guideMusicEnd": "Lily found music—try other commands",
"guideNavStart": "Tell Lily: “Navigate to Shenzhen Airport”",
"guideNavInput": "Navigate to Shenzhen Airport",
"guideNavSend": "Lily will plan the route",
"guideNavEnd": "Navigation set—try other commands",
"guideMeetingStart":
"Tell Lily: “Create a meeting reminder for 3pm tomorrow”",
"guideMeetingInput": "Create a meeting reminder for 3pm tomorrow",
"guideMeetingSend": "Lily will create a meeting reminder",
"guideMeetingEnd": "Reminder created—try other commands",
"guidePhoneStart": "Tell Lily: “Call Mom”",
"guidePhoneInput": "Call Mom",
"guidePhoneSend": "Lily will make the call",
"guidePhoneEnd": "Call placed—try other commands",
"guideSmsStart": "Tell Lily: “Send Dad a text: I’ll be home for dinner”",
"guideSmsInput": "Text Dad: I’ll be home for dinner",
"guideSmsSend": "Lily will send the message",
"guideSmsEnd": "Message sent—voice control is convenient",
// Goods pages common footer (placeholders)
'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans',
'copyrightVoitrans': '© 2025 Voitrans Technologies',
// Meeting goods page (placeholders)
'meetingHeaderDesc1':
'Audio recording, transcription, keyword search, and auto summary.',
'meetingHeaderDesc2':
'Suitable for business meetings, class notes, and interview minutes.',
'meetingAutoRecording': 'Auto recording and segmentation',
'meetingSpeakerTagging': 'Speaker labeling',
'meetingLongAudioTranscription': 'Long audio transcription',
'meetingKeyPointSummary': 'Key point extraction',
'meetingTopicNameSearch': 'Search by topic/name',
'meetingTimelineJump': 'Timeline jump',
'meetingExportSummary': 'Export minutes',
'meetingMultiPlatformShare': 'Share across platforms',
'meetingDisclaimer':
'Use in quiet environments; performance depends on microphone and network.',
// Translation goods page (placeholders)
'transHeaderDesc1': '실시간 동시통역과 텍스트 번역, 저지연 음성 방송.',
'transHeaderDesc2': '여행, 비즈니스, 연설, 교육에 적합합니다.',
'translateZhEn': '중-영 번역',
'lowLatencyVoiceBroadcast': '저지연 음성 방송',
'multiLangTextTranslation': '다국어 텍스트 번역',
'termOptimizationContextPreserve': '용어 최적화 및 문맥 유지',
'lexiconTourBusinessLife': '여행/비즈니스/일상 용어집',
'personalVocabularyMemory': '개인 어휘 메모리',
'conversationSubtitleLargeText': '대화 자막 / 큰 글자 모드',
'colorHighContrast': '높은 색 대비',
'transDisclaimer': '번역 품질은 마이크, 네트워크 지연 및 주변 소음에 따라 달라집니다.',
'trans_001_name': '번역 기본 100',
'trans_002_name': '번역 기본 500',
'trans_003_name': '번역 기본 1000',
'trans_001_desc': '번역 100회 포함(음성/텍스트).',
'trans_002_desc': '번역 500회 포함(음성/텍스트).',
'trans_003_desc': '번역 1000회 포함(음성/텍스트).',
// VIP goods page (placeholders)
'benefitsOverview': '혜택 개요',
'higherQuota': '더 높은 사용 한도',
'lowerUnitPrice': '더 낮은 단가',
'priorityService': '우선 서비스',
'exclusiveSupportChannel': '전용 지원 채널',
'fastResponse': '문제 신속 대응',
'eventsAndDiscounts': '이벤트 및 할인',
'memberExclusiveEvents': '회원 전용 이벤트',
'longTermDiscountPlan': '장기 할인 계획',
'generalPrivileges': '일반 특권',
'earlyAccessNewFeatures': '신기능 사전 이용',
'crossDeviceSync': '디바이스 간 동기화',
'vipDisclaimer': '실제 혜택은 패키지 세부사항에 따라 달라지며 버전에 따라 변경될 수 있습니다.',
};

36
lib/core/translations/language/lt_lt.dart

@ -137,7 +137,8 @@ const Map<String, String> ltLT = {
"initializing": "Inicijuojama...",
"bluetoothInitializationFailure": "Bluetooth paslaugos inicijavimas nepavyko",
"checkingPermissions": "Tikrinami leidimai...",
"lackPermissions": "Trūksta Bluetooth leidimų",
"lackPermissions":
"Trūksta Bluetooth leidimų ir yra reikalinga lokacijos prieiga",
"searchingDevice": "Ieškoma įrenginių...",
"findConnectedDevice": "Rastas prijungtas įrenginys",
"notFound": "Nerasta prijungto Bluetooth įrenginio",
@ -183,22 +184,9 @@ const Map<String, String> ltLT = {
"conferenceAssistant": "Verslo susitikimų asistentas",
"conferenceAssistantInfo":
"Susitikimų protokolo įrašymas realiuoju laiku, daugiakalbis vertimas",
"studyAssistant": "Kalbos mokymosi asistentas",
"studyAssistantInfo": "Tarimo korekcija, kalbėjimo praktika realiuoju laiku",
"travelTranslator": "Kelionių vertimo asistentas",
"travelTranslatorInfo":
"Balso vertimas realiuoju laiku, turistinių objektų pristatymas",
"beSearching": "Ieškoma:",
"noAssistantFound": "Nerasta atitinkamo AI asistento",
"usageStats": "Naudojimo statistika",
"usageStatsInfo": "Peržiūrėkite jūsų naudojimo statistiką",
"scene": "Scenarijus",
"youHaveSelected": "Pasirinkote:",
"newFunction": "Nauja funkcija",
"youChoseTry": "Pasirinkote išbandyti",
"aiSinger": "AI dainininko režimas",
"aiSingerInfo":
"Dainuokite bet kurią dainą mėgstamo dainininko balsu, net savo kompozicijas",
"popularFunction": "Populiarūs funkcijų scenarijai",
"tryNow": "Išbandyti dabar",
// 商务会议助手页
"startMeeting": "Pradėti susitikimą",
@ -214,8 +202,12 @@ const Map<String, String> ltLT = {
'meetingTranscript': 'Susitikimo stenograma',
// 设置页
"systemSettings": "Sistemos nustatymai",
"premiumMember": "Premium narys",
"systemSettings": "Sistemos nustatymai", //系统设置
"vipRecharge": "Premium naryso užsipirkimas", //会员充值
"aiRecharge": "Premium narys", //AI充值
"translationRecharge": "Vertimo užsipirkimas", //翻译充值
"meetingAssistantRecharge": "Susitikimų asistento užsipirkimas", //会议助手充值
"cloudSync": "Synchronizacijos užsipirkimas", //云端同步
"joinDevice": "Prijungtas įrenginys:",
"accountId": "Paskyros ID:",
"systemSetting": "Sistemos nustatymas",
@ -285,7 +277,7 @@ const Map<String, String> ltLT = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Išvalyti pokalbių istoriją",
"online": "Prisijungęs",
"inputMessage": "Įveskite žinutę...",
@ -313,7 +305,7 @@ const Map<String, String> ltLT = {
"swipeUpForMore": "Braukite aukštyn, kad pamatytumėte daugiau",
// Agent controller
'welcomeMessage': 'Sveiki! Aš esu **XiaoYan**, galiu jums padėti:\n\n'
'welcomeMessage': 'Sveiki! Aš esu **Lily**, galiu jums padėti:\n\n'
'• Atsakyti į klausimus ir pateikti informaciją\n\n'
'• Balso vertimas realiuoju laiku\n\n'
'• Rekomenduoti muziką ir tinklalaides\n\n'
@ -703,7 +695,7 @@ const Map<String, String> ltLT = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Įrenginio susiejimas",
"connectYourDeepSoundHeadset": "Prijunkite savo DeepSound ausines",
"connectYourDeepSoundHeadset": "Prijunkite savo Voitrans ausines",
"bind": "Susieti",
"authorizeBind": "Leisti susiejimą",
"enterCode": "Įveskite kodą",
@ -759,7 +751,7 @@ const Map<String, String> ltLT = {
'retryAuthorization': 'Bandyti autorizaciją dar kartą',
'pleaseGrantNecessaryPermissions': 'Suteikite reikiamus leidimus',
'checkFailedRetry': 'Patikrinimas nepavyko, bandykite dar kartą',
'pleaseConnectDeepSoundDevice': 'Prijunkite DeepSound įrenginį',
'pleaseConnectDeepSoundDevice': 'Prijunkite Voitrans įrenginį',
'verificationFailedRetry': 'Patvirtinimas nepavyko, bandykite dar kartą',
'invalidDeviceAddress': 'Neteisingas įrenginio adresas',
'bleDeviceAssociationFailed': 'BLE įrenginio asociacija nepavyko',

34
lib/core/translations/language/lv_lv.dart

@ -137,7 +137,8 @@ const Map<String, String> lvLV = {
"bluetoothInitializationFailure":
"Bluetooth pakalpojuma inicializācija neizdevās",
"checkingPermissions": "Pārbauda atļaujas...",
"lackPermissions": "Trūkst Bluetooth atļauju",
"lackPermissions":
"Trūkst Bluetooth atļauju un ir nepieciešams piekļūt lokācijai",
"searchingDevice": "Meklē ierīces...",
"findConnectedDevice": "Atrasta savienota ierīce",
"notFound": "Neviena savienota Bluetooth ierīce nav atrasta",
@ -182,22 +183,9 @@ const Map<String, String> lvLV = {
"conferenceAssistant": "Biznesa sanāksmju palīgs",
"conferenceAssistantInfo":
"Reāllaika protokolu ierakstīšana, daudzvalodu tulkošana",
"studyAssistant": "Valodu apguves palīgs",
"studyAssistantInfo": "Izrunas korekcija, reāllaika runas prakse",
"travelTranslator": "Ceļojumu tulkošanas palīgs",
"travelTranslatorInfo":
"Reāllaika balss tulkošana, tūrisma objektu iepazīstināšana",
"beSearching": "Meklē:",
"noAssistantFound": "Neviens atbilstošs AI palīgs nav atrasts",
"usageStats": "Pārskatījumu statistika",
"usageStatsInfo": "Pārskatiet jūsu lietotāja pārskatījumu statistiku",
"scene": "Scenārijs",
"youHaveSelected": "Jūs izvēlējāties:",
"newFunction": "Jauna funkcija",
"youChoseTry": "Jūs izvēlējāties mēģināt",
"aiSinger": "AI dziedātāja režīms",
"aiSingerInfo":
"Dziediet jebkuru dziesmu ar sava iecienītākā dziedātāja balsi, pat savas kompozīcijas",
"popularFunction": "Populāri funkciju scenāriji",
"tryNow": "Izmēģināt tagad",
// 商务会议助手页
"startMeeting": "Sākt sapulci",
@ -213,8 +201,12 @@ const Map<String, String> lvLV = {
'meetingTranscript': 'Sapulces atšifrējums',
// 设置页
"systemSettings": "Sistēmas iestatījumi",
"premiumMember": "Premium biedrs",
"systemSettings": "Sistēmas iestatījumi", //系统设置
"vipRecharge": "Premium biedra pārrakstīšana", //会员充值
"aiRecharge": "Premium biedrs", //AI充值
"translationRecharge": "Tulkošanas pārrakstīšana", //翻译充值
"meetingAssistantRecharge": "Sapulces palīgs pārrakstīšana", //会议助手充值
"cloudSync": "Tīkla sincronizācijas pārrakstīšana", //云端同步
"joinDevice": "Savienotā ierīce:",
"accountId": "Konta ID:",
"systemSetting": "Sistēmas iestatījumi",
@ -284,7 +276,7 @@ const Map<String, String> lvLV = {
//Agent 模块
// agent View
"XiaoYan": "SjaoJaņ",
"Lily": "Lily",
"clearChatHistory": "Notīrīt tērzēšanas vēsturi",
"online": "Tiešsaistē",
"inputMessage": "Ievadiet ziņu...",
@ -705,7 +697,7 @@ const Map<String, String> lvLV = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Ierīces savienošana pārī",
"connectYourDeepSoundHeadset": "Savienojiet savas DeepSound austiņas",
"connectYourDeepSoundHeadset": "Savienojiet savas Voitrans austiņas",
"bind": "Saistīt",
"authorizeBind": "Autorizēt saistīšanu",
"enterCode": "Lūdzu, ievadiet kodu",
@ -760,7 +752,7 @@ const Map<String, String> lvLV = {
'retryAuthorization': 'Mēģināt autorizāciju vēlreiz',
'pleaseGrantNecessaryPermissions': 'Lūdzu, piešķiriet nepieciešamās atļaujas',
'checkFailedRetry': 'Pārbaude neizdevās, lūdzu, mēģiniet vēlreiz',
'pleaseConnectDeepSoundDevice': 'Lūdzu, savienojiet DeepSound ierīci',
'pleaseConnectDeepSoundDevice': 'Lūdzu, savienojiet Voitrans ierīci',
'verificationFailedRetry': 'Verifikācija neizdevās, lūdzu, mēģiniet vēlreiz',
'invalidDeviceAddress': 'Nederīga ierīces adrese',
'bleDeviceAssociationFailed': 'BLE ierīces asociācija neizdevās',

36
lib/core/translations/language/ms_my.dart

@ -136,7 +136,8 @@ const Map<String, String> msMY = {
"initializing": "Memulakan...",
"bluetoothInitializationFailure": "Inisialisasi perkhidmatan Bluetooth gagal",
"checkingPermissions": "Menyemak kebenaran...",
"lackPermissions": "Kebenaran Bluetooth tiada",
"lackPermissions":
"Kebenaran Bluetooth tiada dan perlu mengaktifkan lokasi peranti",
"searchingDevice": "Mencari peranti...",
"findConnectedDevice": "Peranti yang disambungkan ditemui",
"notFound": "Tiada peranti Bluetooth yang disambungkan ditemui",
@ -181,22 +182,9 @@ const Map<String, String> msMY = {
"conferenceAssistant": "Pembantu Mesyuarat Perniagaan",
"conferenceAssistantInfo":
"Minit mesyuarat masa nyata, terjemahan pelbagai bahasa",
"studyAssistant": "Pembantu Pembelajaran Bahasa",
"studyAssistantInfo": "Pembetulan sebutan, latihan pertuturan masa nyata",
"travelTranslator": "Pembantu Terjemahan Perjalanan",
"travelTranslatorInfo":
"Terjemahan suara masa nyata, pengenalan tempat pelancongan",
"beSearching": "Mencari:",
"noAssistantFound": "Tiada pembantu AI yang sepadan ditemui",
"usageStats": "Statistik Penggunaan",
"usageStatsInfo": "Lihat statistik penggunaan aplikasi",
"scene": "Senario",
"youHaveSelected": "Anda telah memilih:",
"newFunction": "Fungsi Baharu",
"youChoseTry": "Anda memilih untuk mencuba",
"aiSinger": "Mod Penyanyi AI",
"aiSingerInfo":
"Nyanyikan sebarang lagu dengan suara penyanyi kegemaran anda, malah lagu ciptaan anda sendiri",
"popularFunction": "Senario Fungsi Popular",
"tryNow": "Cuba Sekarang",
// 商务会议助手页
"startMeeting": "Mula Mesyuarat",
@ -212,8 +200,12 @@ const Map<String, String> msMY = {
'meetingTranscript': 'Transkrip Mesyuarat',
// 设置页
"systemSettings": "Tetapan Sistem",
"premiumMember": "Ahli Premium",
"systemSettings": "Tetapan Sistem", //系统设置
"vipRecharge": "Pembayaran Ahli Premium", //会员充值
"aiRecharge": "Ahli Premium", //AI充值
"translationRecharge": "Pembayaran Penterjemahan", //翻译充值
"meetingAssistantRecharge": "Pembayaran Pembantu Mesyuarat", //会议助手充值
"cloudSync": "Pembayaran Sinkronisasi awan", //云端同步
"joinDevice": "Peranti disambungkan:",
"accountId": "ID Akaun:",
"systemSetting": "Tetapan Sistem",
@ -282,7 +274,7 @@ const Map<String, String> msMY = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Kosongkan Sejarah Sembang",
"online": "Dalam Talian",
"inputMessage": "Masukkan mesej...",
@ -309,7 +301,7 @@ const Map<String, String> msMY = {
"swipeUpForMore": "Leret ke atas untuk lebih banyak",
// Agent controller
'welcomeMessage': 'Helo! Saya **XiaoYan**, saya boleh bantu anda:\n\n'
'welcomeMessage': 'Helo! Saya **Lily**, saya boleh bantu anda:\n\n'
'• Jawab soalan dan berikan maklumat\n\n'
'• Terjemahan suara masa nyata\n\n'
'• Cadangkan muzik dan podcast\n\n'
@ -698,7 +690,7 @@ const Map<String, String> msMY = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Pemasangan Peranti",
"connectYourDeepSoundHeadset": "Sambungkan Fon Kepala DeepSound Anda",
"connectYourDeepSoundHeadset": "Sambungkan Fon Kepala Voitrans Anda",
"bind": "Ikat",
"authorizeBind": "Benarkan Pengikatan",
"enterCode": "Sila masukkan kod",
@ -752,7 +744,7 @@ const Map<String, String> msMY = {
'retryAuthorization': 'Cuba Semula Kebenaran',
'pleaseGrantNecessaryPermissions': 'Sila berikan kebenaran yang diperlukan',
'checkFailedRetry': 'Pemeriksaan gagal, sila cuba lagi',
'pleaseConnectDeepSoundDevice': 'Sila sambungkan peranti DeepSound',
'pleaseConnectDeepSoundDevice': 'Sila sambungkan peranti Voitrans',
'verificationFailedRetry': 'Pengesahan gagal, sila cuba lagi',
'invalidDeviceAddress': 'Alamat peranti tidak sah',
'bleDeviceAssociationFailed': 'Perkaitan peranti BLE gagal',

36
lib/core/translations/language/nb_no.dart

@ -136,7 +136,8 @@ const Map<String, String> nbNO = {
"bluetoothInitializationFailure":
"Initialisering av Bluetooth-tjenesten mislyktes",
"checkingPermissions": "Sjekker tillatelser...",
"lackPermissions": "Mangler Bluetooth-tillatelser",
"lackPermissions":
"Mangler Bluetooth-tillatelser og er nødvendig å aktivere lokasjons-tillatelser",
"searchingDevice": "Søker etter enheter...",
"findConnectedDevice": "Fant tilkoblet enhet",
"notFound": "Ingen tilkoblet Bluetooth-enhet funnet",
@ -181,22 +182,9 @@ const Map<String, String> nbNO = {
"conferenceAssistant": "Assistent for forretningsmøter",
"conferenceAssistantInfo":
"Sanntids protokollføring, flerspråklig oversettelse",
"studyAssistant": "Assistent for språklæring",
"studyAssistantInfo": "Uttalekorreksjon, sanntids taleøvelse",
"travelTranslator": "Assistent for reiseoversettelse",
"travelTranslatorInfo":
"Sanntids stemmeoversettelse, introduksjon til turistattraksjoner",
"beSearching": "Søker:",
"noAssistantFound": "Ingen tilsvarende AI-assistent funnet",
"usageStats": "Brukstatistikk",
"usageStatsInfo": "Vis brukstatistikk for din app",
"scene": "Scenario",
"youHaveSelected": "Du har valgt:",
"newFunction": "Ny funksjon",
"youChoseTry": "Du valgte å prøve",
"aiSinger": "AI-sangermodus",
"aiSingerInfo":
"Syng hvilken som helst sang med stemmen til din favorittartist, til og med dine egne komposisjoner",
"popularFunction": "Populære funksjonsscenarier",
"tryNow": "Prøv nå",
// 商务会议助手页
"startMeeting": "Start møte",
@ -212,8 +200,12 @@ const Map<String, String> nbNO = {
'meetingTranscript': 'Møtetranskripsjon',
// 设置页
"systemSettings": "Systeminnstillinger",
"premiumMember": "Premium-medlem",
"systemSettings": "Systeminnstillinger", //系统设置
"vipRecharge": "Premium-medlemsinnskudd", //会员充值
"aiRecharge": "Premium-medlem", //AI充值
"translationRecharge": "Oversettelsespenger", //翻译充值
"meetingAssistantRecharge": "Møteassistentpenger", //会议助手充值
"cloudSync": "Cloud-synchroniseringspenger", //云端同步
"joinDevice": "Tilkoblet enhet:",
"accountId": "Konto-ID:",
"systemSetting": "Systeminnstillinger",
@ -283,7 +275,7 @@ const Map<String, String> nbNO = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Tøm chat-historikk",
"online": "Online",
"inputMessage": "Skriv melding...",
@ -311,7 +303,7 @@ const Map<String, String> nbNO = {
"swipeUpForMore": "Sveip opp for mer",
// Agent controller
'welcomeMessage': 'Hei! Jeg er **XiaoYan**, jeg kan hjelpe deg med:\n\n'
'welcomeMessage': 'Hei! Jeg er **Lily**, jeg kan hjelpe deg med:\n\n'
'• Å svare på spørsmål og gi informasjon\n\n'
'• Sanntids stemmeoversettelse\n\n'
'• Å anbefale musikk og podkaster\n\n'
@ -699,7 +691,7 @@ const Map<String, String> nbNO = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Enhetsparing",
"connectYourDeepSoundHeadset": "Koble til ditt DeepSound-hodesett",
"connectYourDeepSoundHeadset": "Koble til ditt Voitrans-hodesett",
"bind": "Bind",
"authorizeBind": "Autoriser binding",
"enterCode": "Vennligst skriv inn koden",
@ -753,7 +745,7 @@ const Map<String, String> nbNO = {
'retryAuthorization': 'Prøv autorisasjon på nytt',
'pleaseGrantNecessaryPermissions': 'Vennligst gi nødvendige tillatelser',
'checkFailedRetry': 'Kontroll mislyktes, prøv igjen',
'pleaseConnectDeepSoundDevice': 'Vennligst koble til en DeepSound-enhet',
'pleaseConnectDeepSoundDevice': 'Vennligst koble til en Voitrans-enhet',
'verificationFailedRetry': 'Verifisering mislyktes, prøv igjen',
'invalidDeviceAddress': 'Ugyldig enhetsadresse',
'bleDeviceAssociationFailed': 'BLE-enhetsassosiasjon mislyktes',

36
lib/core/translations/language/nl_nl.dart

@ -136,7 +136,8 @@ const Map<String, String> nlNL = {
"bluetoothInitializationFailure":
"Initialisatie van Bluetooth-service mislukt",
"checkingPermissions": "Toestemmingen controleren...",
"lackPermissions": "Bluetooth-toestemmingen ontbreken",
"lackPermissions":
"Bluetooth-toestemmingen ontbreken en zijn nodig om locatie toegang te krijgen",
"searchingDevice": "Apparaten zoeken...",
"findConnectedDevice": "Verbonden apparaat gevonden",
"notFound": "Geen verbonden Bluetooth-apparaat gevonden",
@ -182,22 +183,9 @@ const Map<String, String> nlNL = {
"conferenceAssistant": "Assistent voor zakelijke bijeenkomsten",
"conferenceAssistantInfo":
"Realtime notuleren van vergaderingen, meertalige vertaling",
"studyAssistant": "Assistent voor taalstudie",
"studyAssistantInfo": "Uitspraakcorrectie, realtime spraakoefening",
"travelTranslator": "Assistent voor reisvertaling",
"travelTranslatorInfo":
"Realtime spraakvertaling, introductie van toeristische attracties",
"beSearching": "Zoeken:",
"noAssistantFound": "Geen overeenkomende AI-assistent gevonden",
"usageStats": "Gebruikstatistieken",
"usageStatsInfo": " Bekijk de gebruikstatistieken van uw applicatie",
"scene": "Scenario",
"youHaveSelected": "U heeft geselecteerd:",
"newFunction": "Nieuwe functie",
"youChoseTry": "U koos ervoor om te proberen",
"aiSinger": "AI-zangermodus",
"aiSingerInfo":
"Zing elk nummer met de stem van uw favoriete zanger, zelfs uw eigen composities",
"popularFunction": "Populaire functiescenario's",
"tryNow": "Probeer nu",
// 商务会议助手页
"startMeeting": "Start vergadering",
@ -213,8 +201,12 @@ const Map<String, String> nlNL = {
'meetingTranscript': 'Vergadertranscript',
// 设置页
"systemSettings": "Systeeminstellingen",
"premiumMember": "Premium lid",
"systemSettings": "Systeeminstellingen", //系统设置
"vipRecharge": "Premium lidspayering", //会员充值
"aiRecharge": "Premium lid", //AI充值
"translationRecharge": "Vertalingspayering", //翻译充值
"meetingAssistantRecharge": "Vergaderassistentpayering", //会议助手充值
"cloudSync": "Cloud-synchronisatiepayering", //云端同步
"joinDevice": "Verbonden apparaat:",
"accountId": "Account-ID:",
"systemSetting": "Systeeminstellingen",
@ -283,7 +275,7 @@ const Map<String, String> nlNL = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Chatgeschiedenis wissen",
"online": "Online",
"inputMessage": "Voer bericht in...",
@ -311,7 +303,7 @@ const Map<String, String> nlNL = {
"swipeUpForMore": "Veeg omhoog voor meer",
// Agent controller
'welcomeMessage': 'Hallo! Ik ben **XiaoYan**, ik kan u helpen met:\n\n'
'welcomeMessage': 'Hallo! Ik ben **Lily**, ik kan u helpen met:\n\n'
'• Vragen beantwoorden en informatie verstrekken\n\n'
'• Realtime spraakvertaling\n\n'
'• Muziek en podcasts aanbevelen\n\n'
@ -705,7 +697,7 @@ const Map<String, String> nlNL = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Apparaat koppelen",
"connectYourDeepSoundHeadset": "Verbind uw DeepSound-headset",
"connectYourDeepSoundHeadset": "Verbind uw Voitrans-headset",
"bind": "Koppelen",
"authorizeBind": "Koppeling autoriseren",
"enterCode": "Voer de code in",
@ -760,7 +752,7 @@ const Map<String, String> nlNL = {
'retryAuthorization': 'Autorisatie opnieuw proberen',
'pleaseGrantNecessaryPermissions': 'Verleen de benodigde toestemmingen',
'checkFailedRetry': 'Controle mislukt, probeer het opnieuw',
'pleaseConnectDeepSoundDevice': 'Verbind een DeepSound-apparaat',
'pleaseConnectDeepSoundDevice': 'Verbind een Voitrans-apparaat',
'verificationFailedRetry': 'Verificatie mislukt, probeer het opnieuw',
'invalidDeviceAddress': 'Ongeldig apparaatadres',
'bleDeviceAssociationFailed': 'Associatie van BLE-apparaat mislukt',

36
lib/core/translations/language/pl_pl.dart

@ -136,7 +136,8 @@ const Map<String, String> plPL = {
"bluetoothInitializationFailure":
"Inicjalizacja usługi Bluetooth nie powiodła się",
"checkingPermissions": "Sprawdzanie uprawnień...",
"lackPermissions": "Brak uprawnień Bluetooth",
"lackPermissions":
"Brak uprawnień Bluetooth i jest wymagana prawo dostępu do lokalizacji",
"searchingDevice": "Wyszukiwanie urządzeń...",
"findConnectedDevice": "Znaleziono podłączone urządzenie",
"notFound": "Nie znaleziono podłączonego urządzenia Bluetooth",
@ -183,22 +184,9 @@ const Map<String, String> plPL = {
"conferenceAssistant": "Asystent spotkań biznesowych",
"conferenceAssistantInfo":
"Zapisywanie protokołów w czasie rzeczywistym, tłumaczenie wielojęzyczne",
"studyAssistant": "Asystent nauki języków",
"studyAssistantInfo": "Korekta wymowy, ćwiczenie mowy w czasie rzeczywistym",
"travelTranslator": "Asystent tłumaczenia w podróży",
"travelTranslatorInfo":
"Tłumaczenie głosowe w czasie rzeczywistym, prezentacja atrakcji turystycznych",
"beSearching": "Wyszukiwanie:",
"noAssistantFound": "Nie znaleziono odpowiedniego asystenta AI",
"usageStats": "Statystyki użycia",
"usageStatsInfo": "Przeglądaj statystyki użycia aplikacji",
"scene": "Scenariusz",
"youHaveSelected": "Wybrałeś:",
"newFunction": "Nowa funkcja",
"youChoseTry": "Wybrałeś, aby spróbować",
"aiSinger": "Tryb piosenkarza AI",
"aiSingerInfo":
"Śpiewaj dowolną piosenkę głosem ulubionego piosenkarza, nawet własne kompozycje",
"popularFunction": "Popularne scenariusze funkcji",
"tryNow": "Wypróbuj teraz",
// 商务会议助手页
"startMeeting": "Rozpocznij spotkanie",
@ -214,8 +202,12 @@ const Map<String, String> plPL = {
'meetingTranscript': 'Transkrypcja spotkania',
// 设置页
"systemSettings": "Ustawienia systemowe",
"premiumMember": "Członek Premium",
"systemSettings": "Ustawienia systemowe", //系统设置
"vipRecharge": "Płatność Premium", //会员充值
"aiRecharge": "Członek Premium", //AI充值
"translationRecharge": "Płatność tłumaczenia", //翻译充值
"meetingAssistantRecharge": "Płatność asystenta spotkań", //会议助手充值
"cloudSync": "Płatność synchronizacji w chmurze", //云端同步
"joinDevice": "Podłączone urządzenie:",
"accountId": "ID konta:",
"systemSetting": "Ustawienia systemowe",
@ -286,7 +278,7 @@ const Map<String, String> plPL = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Wyczyść historię czatu",
"online": "Online",
"inputMessage": "Wpisz wiadomość...",
@ -314,7 +306,7 @@ const Map<String, String> plPL = {
"swipeUpForMore": "Przesuń w górę, aby zobaczyć więcej",
// Agent controller
'welcomeMessage': 'Cześć! Jestem **XiaoYan**, mogę Ci pomóc:\n\n'
'welcomeMessage': 'Cześć! Jestem **Lily**, mogę Ci pomóc:\n\n'
'• Odpowiadać na pytania i dostarczać informacji\n\n'
'• Tłumaczyć głosowo w czasie rzeczywistym\n\n'
'• Polecać muzykę i podcasty\n\n'
@ -709,7 +701,7 @@ const Map<String, String> plPL = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Parowanie urządzenia",
"connectYourDeepSoundHeadset": "Połącz swoje słuchawki DeepSound",
"connectYourDeepSoundHeadset": "Połącz swoje słuchawki Voitrans",
"bind": "Powiąż",
"authorizeBind": "Autoryzuj powiązanie",
"enterCode": "Wprowadź kod",
@ -765,7 +757,7 @@ const Map<String, String> plPL = {
'retryAuthorization': 'Spróbuj ponownie autoryzować',
'pleaseGrantNecessaryPermissions': 'Udziel niezbędnych uprawnień',
'checkFailedRetry': 'Sprawdzenie nie powiodło się, spróbuj ponownie',
'pleaseConnectDeepSoundDevice': 'Połącz urządzenie DeepSound',
'pleaseConnectDeepSoundDevice': 'Połącz urządzenie Voitrans',
'verificationFailedRetry': 'Weryfikacja nie powiodła się, spróbuj ponownie',
'invalidDeviceAddress': 'Nieprawidłowy adres urządzenia',
'bleDeviceAssociationFailed': 'Skojarzenie urządzenia BLE nie powiodło się',

131
lib/core/translations/language/pt_pt.dart

@ -137,7 +137,8 @@ const Map<String, String> ptPT = {
"bluetoothInitializationFailure":
"Falha na inicialização do serviço Bluetooth",
"checkingPermissions": "A verificar permissões...",
"lackPermissions": "Faltam permissões de Bluetooth",
"lackPermissions":
"Faltam permissões de Bluetooth e é necessário permitir o acesso à localização",
"searchingDevice": "A procurar dispositivos...",
"findConnectedDevice": "Dispositivo conectado encontrado",
"notFound": "Nenhum dispositivo Bluetooth conectado encontrado",
@ -185,23 +186,17 @@ const Map<String, String> ptPT = {
"conferenceAssistant": "Assistente de Reunião de Negócios",
"conferenceAssistantInfo":
"Gravação de atas em tempo real, tradução multilingue",
"studyAssistant": "Assistente de Aprendizagem de Línguas",
"studyAssistantInfo":
"Correção de pronúncia, prática de conversação em tempo real",
"travelTranslator": "Assistente de Tradução de Viagem",
"travelTranslatorInfo":
"Tradução de voz em tempo real, apresentação de pontos turísticos",
"beSearching": "A pesquisar:",
"noAssistantFound": "Nenhum assistente de IA correspondente encontrado",
"usageStats": "Estatísticas de Uso",
"usageStatsInfo": "Visualize as estatísticas de uso da sua aplicação",
"scene": "Cenário",
"youHaveSelected": "Selecionou:",
"newFunction": "Nova Função",
"youChoseTry": "Escolheu experimentar",
"aiSinger": "Modo Cantor IA",
"aiSingerInfo":
"Cante qualquer música com a voz do seu cantor favorito, até mesmo as suas próprias composições",
"popularFunction": "Cenários de Funções Populares",
"tryNow": "Experimente Agora",
'trans_001_name': 'Tradução Básica 100',
'trans_002_name': 'Tradução Básica 500',
'trans_003_name': 'Tradução Básica 1000',
'trans_001_desc': 'Inclui 100 traduções (voz/texto).',
'trans_002_desc': 'Inclui 500 traduções (voz/texto).',
'trans_003_desc': 'Inclui 1000 traduções (voz/texto).',
// 商务会议助手页
"startMeeting": "Iniciar Reunião",
@ -217,8 +212,12 @@ const Map<String, String> ptPT = {
'meetingTranscript': 'Transcrição da Reunião',
// 设置页
"systemSettings": "Definições do Sistema",
"premiumMember": "Membro Premium",
"systemSettings": "Definições do Sistema", //系统设置
"vipRecharge": "Recarga Premium", //会员充值
"aiRecharge": "Membro Premium", //AI充值
"translationRecharge": "Recarga de Tradução", //翻译充值
"meetingAssistantRecharge": "Recarga do Assistente de Reunião", //会议助手充值
"cloudSync": "Recarga de Sincronização em Nuvem", //云端同步
"joinDevice": "Dispositivo conectado:",
"accountId": "ID da Conta:",
"systemSetting": "Definição do Sistema",
@ -289,7 +288,7 @@ const Map<String, String> ptPT = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Limpar Histórico de Chat",
"online": "Online",
"inputMessage": "Introduzir mensagem...",
@ -317,7 +316,7 @@ const Map<String, String> ptPT = {
"swipeUpForMore": "Deslize para cima para ver mais",
// Agent controller
'welcomeMessage': 'Olá! Eu sou a **XiaoYan**, posso ajudá-lo(a) a:\n\n'
'welcomeMessage': 'Olá! Eu sou a **Lily**, posso ajudá-lo(a) a:\n\n'
'• Responder a perguntas e fornecer informações\n\n'
'• Traduzir voz em tempo real\n\n'
'• Recomendar música e podcasts\n\n'
@ -711,7 +710,7 @@ const Map<String, String> ptPT = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Emparelhamento de Dispositivo",
"connectYourDeepSoundHeadset": "Conecte os seus Auriculares DeepSound",
"connectYourDeepSoundHeadset": "Conecte os seus Auriculares Voitrans",
"bind": "Vincular",
"authorizeBind": "Autorizar Vinculação",
"enterCode": "Introduza o código",
@ -768,7 +767,7 @@ const Map<String, String> ptPT = {
'pleaseGrantNecessaryPermissions':
'Por favor, conceda as permissões necessárias',
'checkFailedRetry': 'Verificação falhou, tente novamente',
'pleaseConnectDeepSoundDevice': 'Por favor, conecte um dispositivo DeepSound',
'pleaseConnectDeepSoundDevice': 'Por favor, conecte um dispositivo Voitrans',
'verificationFailedRetry': 'Verificação falhou, tente novamente',
'invalidDeviceAddress': 'Endereço de dispositivo inválido',
'bleDeviceAssociationFailed': 'Falha na associação do dispositivo BLE',
@ -863,4 +862,90 @@ const Map<String, String> ptPT = {
"乌尔都语": "Urdu",
"波斯语": "Persa",
"斯瓦希里语": "Suaíli",
// Guide overlay keys (placeholders in English)
"sayLilyHint": "Say \"Lily Lily\" to the mic",
"imHere": "I’m here~",
"guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Lily”.",
"aiReplyCompleted": "Lily has finished the reply!",
"aiThinking": "Lily is thinking…",
"guideAwakenSuccess": "Great! Lily is awake—ask it to help.",
"confirmInput": "Confirm Input",
"guideClickSendPrefix": "Tap send, ",
"guideWeatherStart": "Tell Lily: “What’s the weather today?”",
"guideWeatherInput": "What’s the weather today?",
"guideWeatherSend": "Lily will report the weather in real time",
"guideWeatherEnd": "Lily can report weather live—try other commands",
"guideMusicStart": "Tell Lily: “Play some rock music”",
"guideMusicInput": "Play some rock music",
"guideMusicSend": "Lily will find music for you",
"guideMusicEnd": "Lily found music—try other commands",
"guideNavStart": "Tell Lily: “Navigate to Shenzhen Airport”",
"guideNavInput": "Navigate to Shenzhen Airport",
"guideNavSend": "Lily will plan the route",
"guideNavEnd": "Navigation set—try other commands",
"guideMeetingStart":
"Tell Lily: “Create a meeting reminder for 3pm tomorrow”",
"guideMeetingInput": "Create a meeting reminder for 3pm tomorrow",
"guideMeetingSend": "Lily will create a meeting reminder",
"guideMeetingEnd": "Reminder created—try other commands",
"guidePhoneStart": "Tell Lily: “Call Mom”",
"guidePhoneInput": "Call Mom",
"guidePhoneSend": "Lily will make the call",
"guidePhoneEnd": "Call placed—try other commands",
"guideSmsStart": "Tell Lily: “Send Dad a text: I’ll be home for dinner”",
"guideSmsInput": "Text Dad: I’ll be home for dinner",
"guideSmsSend": "Lily will send the message",
"guideSmsEnd": "Message sent—voice control is convenient",
// Goods pages common footer (placeholders)
'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans',
'copyrightVoitrans': '© 2025 Voitrans Technologies',
// Meeting goods page (placeholders)
'meetingHeaderDesc1':
'Audio recording, transcription, keyword search, and auto summary.',
'meetingHeaderDesc2':
'Suitable for business meetings, class notes, and interview minutes.',
'meetingAutoRecording': 'Auto recording and segmentation',
'meetingSpeakerTagging': 'Speaker labeling',
'meetingLongAudioTranscription': 'Long audio transcription',
'meetingKeyPointSummary': 'Key point extraction',
'meetingTopicNameSearch': 'Search by topic/name',
'meetingTimelineJump': 'Timeline jump',
'meetingExportSummary': 'Export minutes',
'meetingMultiPlatformShare': 'Share across platforms',
'meetingDisclaimer':
'Use in quiet environments; performance depends on microphone and network.',
// Translation goods page (placeholders)
'transHeaderDesc1':
'Interpretação simultânea e tradução de texto em tempo real, com voz de baixa latência.',
'transHeaderDesc2': 'Adequado para viagens, negócios, palestras e ensino.',
'translateZhEn': 'Tradução Chinês-Inglês',
'lowLatencyVoiceBroadcast': 'Transmissão de voz de baixa latência',
'multiLangTextTranslation': 'Tradução de texto multilingue',
'termOptimizationContextPreserve':
'Otimização de terminologia e preservação de contexto',
'lexiconTourBusinessLife': 'Léxicos de viagem/negócios/vida',
'personalVocabularyMemory': 'Memória de vocabulário pessoal',
'conversationSubtitleLargeText':
'Legendagem de conversas / modo de texto grande',
'colorHighContrast': 'Alto contraste de cor',
'transDisclaimer':
'O desempenho da tradução depende do microfone, da latência da rede e do ruído ambiente.',
// VIP goods page (placeholders)
'benefitsOverview': 'Visão geral de benefícios',
'higherQuota': 'Maior quota de utilização',
'lowerUnitPrice': 'Preço unitário inferior',
'priorityService': 'Serviço prioritário',
'exclusiveSupportChannel': 'Canal de suporte dedicado',
'fastResponse': 'Resposta rápida a problemas',
'eventsAndDiscounts': 'Eventos e descontos',
'memberExclusiveEvents': 'Eventos exclusivos para membros',
'longTermDiscountPlan': 'Plano de desconto a longo prazo',
'generalPrivileges': 'Privilégios gerais',
'earlyAccessNewFeatures': 'Acesso antecipado a novas funcionalidades',
'crossDeviceSync': 'Sincronização entre dispositivos',
'vipDisclaimer':
'Os benefícios reais dependem dos detalhes do pacote e podem mudar entre versões.',
};

37
lib/core/translations/language/ro_ro.dart

@ -137,7 +137,8 @@ const Map<String, String> roRO = {
"bluetoothInitializationFailure":
"Inițializarea serviciului Bluetooth a eșuat",
"checkingPermissions": "Se verifică permisiunile...",
"lackPermissions": "Lipsesc permisiunile Bluetooth",
"lackPermissions":
"Lipsesc permisiunile Bluetooth și este necesar să permiteți accesul la localizare",
"searchingDevice": "Se caută dispozitive...",
"findConnectedDevice": "Dispozitiv conectat găsit",
"notFound": "Niciun dispozitiv Bluetooth conectat nu a fost găsit",
@ -184,23 +185,9 @@ const Map<String, String> roRO = {
"conferenceAssistant": "Asistent pentru ședințe de afaceri",
"conferenceAssistantInfo":
"Înregistrare în timp real a proceselor-verbale, traducere multilingvă",
"studyAssistant": "Asistent pentru învățarea limbilor străine",
"studyAssistantInfo":
"Corectarea pronunției, practicarea vorbirii în timp real",
"travelTranslator": "Asistent de traducere pentru călătorii",
"travelTranslatorInfo":
"Traducere vocală în timp real, prezentarea atracțiilor turistice",
"beSearching": "Se caută:",
"noAssistantFound": "Niciun asistent AI corespunzător nu a fost găsit",
"usageStats": "Statistici de utilizare",
"usageStatsInfo": "Vizualizați istoricul utilizării aplicației",
"scene": "Scenariu",
"youHaveSelected": "Ați selectat:",
"newFunction": "Funcție nouă",
"youChoseTry": "Ați ales să încercați",
"aiSinger": "Modul cântăreț AI",
"aiSingerInfo":
"Cântați orice melodie cu vocea cântărețului preferat, chiar și propriile compoziții",
"popularFunction": "Scenarii de funcții populare",
"tryNow": "Încearcă acum",
// 商务会议助手页
"startMeeting": "Începe ședința",
@ -216,8 +203,12 @@ const Map<String, String> roRO = {
'meetingTranscript': 'Transcriere ședință',
// 设置页
"systemSettings": "Setări de sistem",
"premiumMember": "Membru Premium",
"systemSettings": "Setări de sistem", //系统设置
"vipRecharge": "Recarga Premium", //会员充值
"aiRecharge": "Membru Premium", //AI充值
"translationRecharge": "Recarga de traducere", //翻译充值
"meetingAssistantRecharge": "Recarga de asistent ședință", //会议助手充值
"cloudSync": "Recarga de sincronizare în cloud", //云端同步
"joinDevice": "Dispozitiv conectat:",
"accountId": "ID cont:",
"systemSetting": "Setări de sistem",
@ -288,7 +279,7 @@ const Map<String, String> roRO = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Șterge istoricul chatului",
"online": "Online",
"inputMessage": "Introduceți mesaj...",
@ -316,7 +307,7 @@ const Map<String, String> roRO = {
"swipeUpForMore": "Glisați în sus pentru mai mult",
// Agent controller
'welcomeMessage': 'Bună! Sunt **XiaoYan**, vă pot ajuta cu:\n\n'
'welcomeMessage': 'Bună! Sunt **Lily**, vă pot ajuta cu:\n\n'
'• Răspuns la întrebări și furnizare de informații\n\n'
'• Traducere vocală în timp real\n\n'
'• Recomandare de muzică și podcasturi\n\n'
@ -713,7 +704,7 @@ const Map<String, String> roRO = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Asociere dispozitiv",
"connectYourDeepSoundHeadset": "Conectați-vă căștile DeepSound",
"connectYourDeepSoundHeadset": "Conectați-vă căștile Voitrans",
"bind": "Leagă",
"authorizeBind": "Autorizează legarea",
"enterCode": "Introduceți codul",
@ -768,7 +759,7 @@ const Map<String, String> roRO = {
'retryAuthorization': 'Reîncearcă autorizarea',
'pleaseGrantNecessaryPermissions': 'Acordați permisiunile necesare',
'checkFailedRetry': 'Verificare eșuată, reîncercați',
'pleaseConnectDeepSoundDevice': 'Conectați un dispozitiv DeepSound',
'pleaseConnectDeepSoundDevice': 'Conectați un dispozitiv Voitrans',
'verificationFailedRetry': 'Verificare eșuată, reîncercați',
'invalidDeviceAddress': 'Adresă de dispozitiv invalidă',
'bleDeviceAssociationFailed': 'Asocierea dispozitivului BLE a eșuat',

128
lib/core/translations/language/ru_ru.dart

@ -137,7 +137,8 @@ const Map<String, String> ruRU = {
"initializing": "Инициализация...",
"bluetoothInitializationFailure": "Ошибка инициализации службы Bluetooth",
"checkingPermissions": "Проверка разрешений...",
"lackPermissions": "Отсутствуют разрешения Bluetooth",
"lackPermissions":
"Отсутствуют разрешения Bluetooth и необходимо разрешить доступ к местоположению",
"searchingDevice": "Поиск устройств...",
"findConnectedDevice": "Найдено подключенное устройство",
"notFound": "Подключенное устройство Bluetooth не найдено",
@ -183,23 +184,17 @@ const Map<String, String> ruRU = {
"conferenceAssistant": "Помощник для деловых встреч",
"conferenceAssistantInfo":
"Запись протоколов в реальном времени, многоязычный перевод",
"studyAssistant": "Помощник в изучении языков",
"studyAssistantInfo":
"Коррекция произношения, практика разговорной речи в реальном времени",
"travelTranslator": "Помощник-переводчик для путешествий",
"travelTranslatorInfo":
"Голосовой перевод в реальном времени, описание туристических достопримечательностей",
"beSearching": "Поиск:",
"noAssistantFound": "Соответствующий AI-помощник не найден",
"usageStats": "Статистика использования",
"usageStatsInfo": "Просмотрите статистику использования вашего приложения",
"scene": "Сценарий",
"youHaveSelected": "Вы выбрали:",
"newFunction": "Новая функция",
"youChoseTry": "Вы решили попробовать",
"aiSinger": "Режим AI-певца",
"aiSingerInfo":
"Пойте любую песню голосом вашего любимого исполнителя, даже ваши собственные композиции",
"popularFunction": "Популярные функциональные сценарии",
"tryNow": "Попробовать сейчас",
'trans_001_name': 'Перевод Базовый 100',
'trans_002_name': 'Перевод Базовый 500',
'trans_003_name': 'Перевод Базовый 1000',
'trans_001_desc': 'Включает 100 переводов (голос/текст).',
'trans_002_desc': 'Включает 500 переводов (голос/текст).',
'trans_003_desc': 'Включает 1000 переводов (голос/текст).',
// 商务会议助手页
"startMeeting": "Начать встречу",
@ -215,8 +210,12 @@ const Map<String, String> ruRU = {
'meetingTranscript': 'Транскрипт встречи',
// 设置页
"systemSettings": "Системные настройки",
"premiumMember": "Премиум-участник",
"systemSettings": "Системные настройки", //系统设置
"vipRecharge": "Пополнение премиум-члена", //会员充值
"aiRecharge": "Премиум-участник", //AI充值
"translationRecharge": "Пополнение перевода", //翻译充值
"meetingAssistantRecharge": "Пополнение помощника встречи", //会议助手充值
"cloudSync": "Пополнение синхронизации в облаке", //云端同步
"joinDevice": "Подключенное устройство:",
"accountId": "ID аккаунта:",
"systemSetting": "Системные настройки",
@ -285,7 +284,7 @@ const Map<String, String> ruRU = {
//Agent 模块
// agent View
"XiaoYan": "СяоЯнь",
"Lily": "Lily",
"clearChatHistory": "Очистить историю чата",
"online": "В сети",
"inputMessage": "Введите сообщение...",
@ -761,7 +760,7 @@ const Map<String, String> ruRU = {
'pleaseGrantNecessaryPermissions':
'Пожалуйста, предоставьте необходимые разрешения',
'checkFailedRetry': 'Проверка не удалась, попробуйте еще раз',
'pleaseConnectDeepSoundDevice': 'Пожалуйста, подключите устройство DeepSound',
'pleaseConnectDeepSoundDevice': 'Пожалуйста, подключите устройство Voitrans',
'verificationFailedRetry': 'Проверка не удалась, попробуйте еще раз',
'invalidDeviceAddress': 'Неверный адрес устройства',
'bleDeviceAssociationFailed': 'Не удалось связать устройство BLE',
@ -856,4 +855,91 @@ const Map<String, String> ruRU = {
"乌尔都语": "Урду",
"波斯语": "Персидский",
"斯瓦希里语": "Суахили",
// Guide overlay keys (placeholders in English)
"sayLilyHint": "Say \"Lily Lily\" to the mic",
"imHere": "I’m here~",
"guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Lily”.",
"aiReplyCompleted": "Lily has finished the reply!",
"aiThinking": "Lily is thinking…",
"guideAwakenSuccess": "Great! Lily is awake—ask it to help.",
"confirmInput": "Confirm Input",
"guideClickSendPrefix": "Tap send, ",
"guideWeatherStart": "Tell Lily: “What’s the weather today?”",
"guideWeatherInput": "What’s the weather today?",
"guideWeatherSend": "Lily will report the weather in real time",
"guideWeatherEnd": "Lily can report weather live—try other commands",
"guideMusicStart": "Tell Lily: “Play some rock music”",
"guideMusicInput": "Play some rock music",
"guideMusicSend": "Lily will find music for you",
"guideMusicEnd": "Lily found music—try other commands",
"guideNavStart": "Tell Lily: “Navigate to Shenzhen Airport”",
"guideNavInput": "Navigate to Shenzhen Airport",
"guideNavSend": "Lily will plan the route",
"guideNavEnd": "Navigation set—try other commands",
"guideMeetingStart":
"Tell Lily: “Create a meeting reminder for 3pm tomorrow”",
"guideMeetingInput": "Create a meeting reminder for 3pm tomorrow",
"guideMeetingSend": "Lily will create a meeting reminder",
"guideMeetingEnd": "Reminder created—try other commands",
"guidePhoneStart": "Tell Lily: “Call Mom”",
"guidePhoneInput": "Call Mom",
"guidePhoneSend": "Lily will make the call",
"guidePhoneEnd": "Call placed—try other commands",
"guideSmsStart": "Tell Lily: “Send Dad a text: I’ll be home for dinner”",
"guideSmsInput": "Text Dad: I’ll be home for dinner",
"guideSmsSend": "Lily will send the message",
"guideSmsEnd": "Message sent—voice control is convenient",
// Goods pages common footer (placeholders)
'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans',
'copyrightVoitrans': '© 2025 Voitrans Technologies',
// Meeting goods page (placeholders)
'meetingHeaderDesc1':
'Audio recording, transcription, keyword search, and auto summary.',
'meetingHeaderDesc2':
'Suitable for business meetings, class notes, and interview minutes.',
'meetingAutoRecording': 'Auto recording and segmentation',
'meetingSpeakerTagging': 'Speaker labeling',
'meetingLongAudioTranscription': 'Long audio transcription',
'meetingKeyPointSummary': 'Key point extraction',
'meetingTopicNameSearch': 'Search by topic/name',
'meetingTimelineJump': 'Timeline jump',
'meetingExportSummary': 'Export minutes',
'meetingMultiPlatformShare': 'Share across platforms',
'meetingDisclaimer':
'Use in quiet environments; performance depends on microphone and network.',
// Translation goods page (placeholders)
'transHeaderDesc1':
'Синхронный перевод и перевод текста в реальном времени с низкой задержкой голосового озвучивания.',
'transHeaderDesc2':
'Подходит для путешествий, бизнеса, выступлений и обучения.',
'translateZhEn': 'Китайско-английский перевод',
'lowLatencyVoiceBroadcast': 'Голосовое вещание с низкой задержкой',
'multiLangTextTranslation': 'Многоязычный перевод текста',
'termOptimizationContextPreserve':
'Оптимизация терминологии и сохранение контекста',
'lexiconTourBusinessLife':
'Лексика для путешествий/бизнеса/повседневной жизни',
'personalVocabularyMemory': 'Память персонального словаря',
'conversationSubtitleLargeText': 'Субтитры беседы / режим крупных шрифтов',
'colorHighContrast': 'Высокая контрастность цветов',
'transDisclaimer':
'Качество перевода зависит от микрофона, сетевой задержки и фонового шума.',
// VIP goods page (placeholders)
'benefitsOverview': 'Обзор преимуществ',
'higherQuota': 'Более высокая квота использования',
'lowerUnitPrice': 'Низкая цена за единицу',
'priorityService': 'Приоритетное обслуживание',
'exclusiveSupportChannel': 'Выделенный канал поддержки',
'fastResponse': 'Быстрый отклик на проблемы',
'eventsAndDiscounts': 'События и скидки',
'memberExclusiveEvents': 'Эксклюзивные мероприятия для участников',
'longTermDiscountPlan': 'Долгосрочный план скидок',
'generalPrivileges': 'Общие привилегии',
'earlyAccessNewFeatures': 'Ранний доступ к новым функциям',
'crossDeviceSync': 'Синхронизация между устройствами',
'vipDisclaimer':
'Фактические преимущества зависят от деталей пакета и могут меняться с версиями.',
};

36
lib/core/translations/language/sk_sk.dart

@ -136,7 +136,8 @@ const Map<String, String> skSK = {
"initializing": "Inicializácia...",
"bluetoothInitializationFailure": "Inicializácia služby Bluetooth zlyhala",
"checkingPermissions": "Kontrola povolení...",
"lackPermissions": "Chýbajú povolenia Bluetooth",
"lackPermissions":
"Chýbajú povolenia Bluetooth a je potrebné povoliť prístup k lokáli",
"searchingDevice": "Vyhľadávanie zariadení...",
"findConnectedDevice": "Nájdené pripojené zariadenie",
"notFound": "Nenájdené žiadne pripojené Bluetooth zariadenie",
@ -182,22 +183,9 @@ const Map<String, String> skSK = {
"conferenceAssistant": "Asistent pre obchodné stretnutia",
"conferenceAssistantInfo":
"Záznam zápisnice v reálnom čase, viacjazyčný preklad",
"studyAssistant": "Asistent pre štúdium jazykov",
"studyAssistantInfo": "Oprava výslovnosti, prax reči v reálnom čase",
"travelTranslator": "Asistent pre preklad na cestách",
"travelTranslatorInfo":
"Hlasový preklad v reálnom čase, predstavenie turistických atrakcií",
"beSearching": "Hľadám:",
"noAssistantFound": "Nenájdený žiadny zodpovedajúci AI asistent",
"usageStats": "Statistiky využitia",
"usageStatsInfo": "Zobrazte vaše využitie aplikácie",
"scene": "Scenár",
"youHaveSelected": "Vybrali ste:",
"newFunction": "Nová funkcia",
"youChoseTry": "Rozhodli ste sa vyskúšať",
"aiSinger": "Režim AI speváka",
"aiSingerInfo":
"Spievajte akúkoľvek pieseň hlasom vášho obľúbeného speváka, dokonca aj vlastné skladby",
"popularFunction": "Populárne funkčné scenáre",
"tryNow": "Vyskúšať teraz",
// 商务会议助手页
"startMeeting": "Začať stretnutie",
@ -213,8 +201,12 @@ const Map<String, String> skSK = {
'meetingTranscript': 'Prepis stretnutia',
// 设置页
"systemSettings": "Systémové nastavenia",
"premiumMember": "Prémium člen",
"systemSettings": "Systémové nastavenia", //系统设置
"vipRecharge": "Nákup prémium členstva", //会员充值
"aiRecharge": "Prémium člen", //AI充值
"translationRecharge": "Nákup prekladov", //翻译充值
"meetingAssistantRecharge": "Nákup asistentu stretnutia", //会议助手充值
"cloudSync": "Nákup synchronizácie v cloude", //云端同步
"joinDevice": "Pripojené zariadenie:",
"accountId": "ID účtu:",
"systemSetting": "Systémové nastavenie",
@ -283,7 +275,7 @@ const Map<String, String> skSK = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Vymazať históriu chatu",
"online": "Online",
"inputMessage": "Zadajte správu...",
@ -310,7 +302,7 @@ const Map<String, String> skSK = {
"swipeUpForMore": "Potiahnite nahor pre viac",
// Agent controller
'welcomeMessage': 'Ahoj! Som **XiaoYan**, môžem vám pomôcť:\n\n'
'welcomeMessage': 'Ahoj! Som **Lily**, môžem vám pomôcť:\n\n'
'• Odpovedať na otázky a poskytovať informácie\n\n'
'• Hlasový preklad v reálnom čase\n\n'
'• Odporúčať hudbu a podcasty\n\n'
@ -699,7 +691,7 @@ const Map<String, String> skSK = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Párovanie zariadenia",
"connectYourDeepSoundHeadset": "Pripojte svoje slúchadlá DeepSound",
"connectYourDeepSoundHeadset": "Pripojte svoje slúchadlá Voitrans",
"bind": "Prepojiť",
"authorizeBind": "Autorizovať prepojenie",
"enterCode": "Zadajte kód",
@ -754,7 +746,7 @@ const Map<String, String> skSK = {
'retryAuthorization': 'Znova autorizovať',
'pleaseGrantNecessaryPermissions': 'Udeľte potrebné povolenia',
'checkFailedRetry': 'Kontrola zlyhala, skúste to znova',
'pleaseConnectDeepSoundDevice': 'Pripojte zariadenie DeepSound',
'pleaseConnectDeepSoundDevice': 'Pripojte zariadenie Voitrans',
'verificationFailedRetry': 'Overenie zlyhalo, skúste to znova',
'invalidDeviceAddress': 'Neplatná adresa zariadenia',
'bleDeviceAssociationFailed': 'Priradenie zariadenia BLE zlyhalo',

36
lib/core/translations/language/sl_si.dart

@ -136,7 +136,8 @@ const Map<String, String> slSI = {
"bluetoothInitializationFailure":
"Inicializacija storitve Bluetooth ni uspela",
"checkingPermissions": "Preverjanje dovoljenj...",
"lackPermissions": "Manjkajo dovoljenja za Bluetooth",
"lackPermissions":
"Manjkajo dovoljenja za Bluetooth in je potrebno omogočiti dostop do lokacije",
"searchingDevice": "Iskanje naprav...",
"findConnectedDevice": "Najdena povezana naprava",
"notFound": "Nobena povezana naprava Bluetooth ni bila najdena",
@ -182,22 +183,9 @@ const Map<String, String> slSI = {
"conferenceAssistant": "Pomočnik za poslovne sestanke",
"conferenceAssistantInfo":
"Zapisovanje zapisnikov v realnem času, večjezično prevajanje",
"studyAssistant": "Pomočnik za učenje jezikov",
"studyAssistantInfo": "Popravek izgovorjave, vadba govorjenja v realnem času",
"travelTranslator": "Pomočnik za prevajanje na potovanjih",
"travelTranslatorInfo":
"Glasovno prevajanje v realnem času, predstavitev turističnih znamenitosti",
"beSearching": "Iskanje:",
"noAssistantFound": "Ni bil najden noben ustrezen pomočnik AI",
"usageStats": "Statistika uporabe",
"usageStatsInfo": "Pregledajte vaše uporabo aplikacije",
"scene": "Scenarij",
"youHaveSelected": "Izbrali ste:",
"newFunction": "Nova funkcija",
"youChoseTry": "Izbrali ste poskusiti",
"aiSinger": "Način AI pevca",
"aiSingerInfo":
"Zapojte katero koli pesem z glasom vašega najljubšega pevca, celo lastne skladbe",
"popularFunction": "Priljubljeni funkcijski scenariji",
"tryNow": "Poskusi zdaj",
// 商务会议助手页
"startMeeting": "Začni sestanek",
@ -213,8 +201,12 @@ const Map<String, String> slSI = {
'meetingTranscript': 'Prepis sestanka',
// 设置页
"systemSettings": "Sistemske nastavitve",
"premiumMember": "Premium član",
"systemSettings": "Sistemske nastavitve", //系统设置
"vipRecharge": "Nákup premium člana", //会员充值
"aiRecharge": "Premium član", //AI充值
"translationRecharge": "Nákup prevajanja", //翻译充值
"meetingAssistantRecharge": "Nákup asistenta sestanka", //会议助手充值
"cloudSync": "Nákup sinkronizacije v oblaku", //云端同步
"joinDevice": "Povezana naprava:",
"accountId": "ID računa:",
"systemSetting": "Sistemska nastavitev",
@ -284,7 +276,7 @@ const Map<String, String> slSI = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Počisti zgodovino klepeta",
"online": "Na spletu",
"inputMessage": "Vnesite sporočilo...",
@ -311,7 +303,7 @@ const Map<String, String> slSI = {
"swipeUpForMore": "Povlecite navzgor za več",
// Agent controller
'welcomeMessage': 'Živjo! Sem **XiaoYan**, lahko vam pomagam:\n\n'
'welcomeMessage': 'Živjo! Sem **Lily**, lahko vam pomagam:\n\n'
'• Odgovarjam na vprašanja in nudim informacije\n\n'
'• Glasovno prevajanje v realnem času\n\n'
'• Priporočam glasbo in podcaste\n\n'
@ -704,7 +696,7 @@ const Map<String, String> slSI = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Seznanjanje naprave",
"connectYourDeepSoundHeadset": "Povežite svoje slušalke DeepSound",
"connectYourDeepSoundHeadset": "Povežite svoje slušalke Voitrans",
"bind": "Poveži",
"authorizeBind": "Avtoriziraj povezavo",
"enterCode": "Vnesite kodo",
@ -759,7 +751,7 @@ const Map<String, String> slSI = {
'retryAuthorization': 'Ponovno avtoriziraj',
'pleaseGrantNecessaryPermissions': 'Podelite potrebna dovoljenja',
'checkFailedRetry': 'Preverjanje ni uspelo, poskusite znova',
'pleaseConnectDeepSoundDevice': 'Povežite napravo DeepSound',
'pleaseConnectDeepSoundDevice': 'Povežite napravo Voitrans',
'verificationFailedRetry': 'Preverjanje ni uspelo, poskusite znova',
'invalidDeviceAddress': 'Neveljaven naslov naprave',
'bleDeviceAssociationFailed': 'Povezovanje naprave BLE ni uspelo',

36
lib/core/translations/language/sr_rs.dart

@ -136,7 +136,8 @@ const Map<String, String> srRS = {
"bluetoothInitializationFailure":
"Neuspešna inicijalizacija Bluetooth servisa",
"checkingPermissions": "Provera dozvola...",
"lackPermissions": "Nedostaju Bluetooth dozvole",
"lackPermissions":
"Nedostaju Bluetooth dozvole i je potrebno omogućiti pristup lokaciji",
"searchingDevice": "Pretraga uređaja...",
"findConnectedDevice": "Pronađen povezan uređaj",
"notFound": "Nije pronađen povezan Bluetooth uređaj",
@ -181,22 +182,9 @@ const Map<String, String> srRS = {
"conferenceAssistant": "Asistent za poslovne sastanke",
"conferenceAssistantInfo":
"Beleženje zapisnika u realnom vremenu, višejezično prevođenje",
"studyAssistant": "Asistent za učenje jezika",
"studyAssistantInfo": "Korekcija izgovora, vežbanje govora u realnom vremenu",
"travelTranslator": "Asistent za prevođenje na putovanjima",
"travelTranslatorInfo":
"Glasovno prevođenje u realnom vremenu, predstavljanje turističkih atrakcija",
"beSearching": "Pretraga:",
"noAssistantFound": "Nije pronađen odgovarajući AI asistent",
"usageStats": "Statistika korišćenja",
"usageStatsInfo": "Pregledajte vaše korišćenje aplikacije",
"scene": "Scena",
"youHaveSelected": "Izabrali ste:",
"newFunction": "Nova funkcija",
"youChoseTry": "Izabrali ste da probate",
"aiSinger": "AI pevač mod",
"aiSingerInfo":
"Pevajte bilo koju pesmu glasom svog omiljenog pevača, čak i sopstvene kompozicije",
"popularFunction": "Popularne scene funkcija",
"tryNow": "Probaj sada",
// 商务会议助手页
"startMeeting": "Započni sastanak",
@ -212,8 +200,12 @@ const Map<String, String> srRS = {
'meetingTranscript': 'Transkript sastanka',
// 设置页
"systemSettings": "Sistemska podešavanja",
"premiumMember": "Premium član",
"systemSettings": "Sistemska podešavanja", //系统设置
"vipRecharge": "Nákup premium člana", //会员充值
"aiRecharge": "Premium član", //AI充值
"translationRecharge": "Nákup prevajanja", //翻译充值
"meetingAssistantRecharge": "Nákup asistenta sastanka", //会议助手充值
"cloudSync": "Nákup sinkronizacije u oblaku", //云端同步
"joinDevice": "Povezan uređaj:",
"accountId": "ID naloga:",
"systemSetting": "Sistemsko podešavanje",
@ -282,7 +274,7 @@ const Map<String, String> srRS = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Obriši istoriju ćaskanja",
"online": "Na mreži",
"inputMessage": "Unesite poruku...",
@ -309,7 +301,7 @@ const Map<String, String> srRS = {
"swipeUpForMore": "Prevucite nagore za više",
// Agent controller
'welcomeMessage': 'Zdravo! Ja sam **XiaoYan**, mogu vam pomoći:\n\n'
'welcomeMessage': 'Zdravo! Ja sam **Lily**, mogu vam pomoći:\n\n'
'• Da odgovaram na pitanja i pružam informacije\n\n'
'• Glasovno prevođenje u realnom vremenu\n\n'
'• Da preporučujem muziku i podkaste\n\n'
@ -699,7 +691,7 @@ const Map<String, String> srRS = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Uparivanje uređaja",
"connectYourDeepSoundHeadset": "Povežite svoje DeepSound slušalice",
"connectYourDeepSoundHeadset": "Povežite svoje Voitrans slušalice",
"bind": "Poveži",
"authorizeBind": "Autorizuj povezivanje",
"enterCode": "Unesite kod",
@ -754,7 +746,7 @@ const Map<String, String> srRS = {
'retryAuthorization': 'Pokušaj ponovo autorizaciju',
'pleaseGrantNecessaryPermissions': 'Dajte potrebne dozvole',
'checkFailedRetry': 'Neuspešna provera, pokušajte ponovo',
'pleaseConnectDeepSoundDevice': 'Povežite DeepSound uređaj',
'pleaseConnectDeepSoundDevice': 'Povežite Voitrans uređaj',
'verificationFailedRetry': 'Neuspešna verifikacija, pokušajte ponovo',
'invalidDeviceAddress': 'Nevažeća adresa uređaja',
'bleDeviceAssociationFailed': 'Neuspešno povezivanje BLE uređaja',

37
lib/core/translations/language/sv_se.dart

@ -136,7 +136,8 @@ const Map<String, String> svSE = {
"bluetoothInitializationFailure":
"Initiering av Bluetooth-tjänst misslyckades",
"checkingPermissions": "Kontrollerar behörigheter...",
"lackPermissions": "Saknar Bluetooth-behörigheter",
"lackPermissions":
"Saknar Bluetooth-behörigheter och kräver att du tillåter åtkomst till plats",
"searchingDevice": "Söker efter enheter...",
"findConnectedDevice": "Hittade ansluten enhet",
"notFound": "Ingen ansluten Bluetooth-enhet hittades",
@ -181,23 +182,9 @@ const Map<String, String> svSE = {
"conferenceAssistant": "Affärsmötesassistent",
"conferenceAssistantInfo":
"Realtidsinspelning av mötesprotokoll, flerspråkig översättning",
"studyAssistant": "Språkinlärningsassistent",
"studyAssistantInfo":
"Uttalskorrigering, realtidsövning av muntlig färdighet",
"travelTranslator": "Reseöversättningsassistent",
"travelTranslatorInfo":
"Realtids röstöversättning, introduktion till turistattraktioner",
"beSearching": "Söker:",
"noAssistantFound": "Ingen motsvarande AI-assistent hittades",
"usageStats": "Användningsstatistik",
"usageStatsInfo": "Visa din användningsstatistik",
"scene": "Scenario",
"youHaveSelected": "Du har valt:",
"newFunction": "Ny funktion",
"youChoseTry": "Du valde att prova",
"aiSinger": "AI-sångarläge",
"aiSingerInfo":
"Sjung vilken låt som helst med din favoritsångares röst, även dina egna kompositioner",
"popularFunction": "Populära funktionsscenarier",
"tryNow": "Prova nu",
// 商务会议助手页
"startMeeting": "Starta möte",
@ -213,8 +200,12 @@ const Map<String, String> svSE = {
'meetingTranscript': 'Mötesutskrift',
// 设置页
"systemSettings": "Systeminställningar",
"premiumMember": "Premium-medlem",
"systemSettings": "Systeminställningar", //系统设置
"vipRecharge": "Premium-låntagning", //会员充值
"aiRecharge": "Premium-medlem", //AI充值
"translationRecharge": "Översättningslåntagning", //翻译充值
"meetingAssistantRecharge": "Mötesassistentlåntagning", //会议助手充值
"cloudSync": "Molnsynkronisering", //云端同步
"joinDevice": "Ansluten enhet:",
"accountId": "Konto-ID:",
"systemSetting": "Systeminställning",
@ -283,7 +274,7 @@ const Map<String, String> svSE = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Rensa chatthistorik",
"online": "Online",
"inputMessage": "Skriv meddelande...",
@ -310,7 +301,7 @@ const Map<String, String> svSE = {
"swipeUpForMore": "Svep upp för mer",
// Agent controller
'welcomeMessage': 'Hej! Jag är **XiaoYan**, jag kan hjälpa dig med:\n\n'
'welcomeMessage': 'Hej! Jag är **Lily**, jag kan hjälpa dig med:\n\n'
'• Svara på frågor och ge information\n\n'
'• Realtids röstöversättning\n\n'
'• Rekommendera musik och poddar\n\n'
@ -699,7 +690,7 @@ const Map<String, String> svSE = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Enhetsparkoppling",
"connectYourDeepSoundHeadset": "Anslut dina DeepSound-hörlurar",
"connectYourDeepSoundHeadset": "Anslut dina Voitrans-hörlurar",
"bind": "Bind",
"authorizeBind": "Auktorisera bindning",
"enterCode": "Ange koden",
@ -753,7 +744,7 @@ const Map<String, String> svSE = {
'retryAuthorization': 'Försök auktorisera igen',
'pleaseGrantNecessaryPermissions': 'Bevilja nödvändiga behörigheter',
'checkFailedRetry': 'Kontroll misslyckades, försök igen',
'pleaseConnectDeepSoundDevice': 'Anslut en DeepSound-enhet',
'pleaseConnectDeepSoundDevice': 'Anslut en Voitrans-enhet',
'verificationFailedRetry': 'Verifiering misslyckades, försök igen',
'invalidDeviceAddress': 'Ogiltig enhetsadress',
'bleDeviceAssociationFailed': 'BLE-enhetsassociation misslyckades',

30
lib/core/translations/language/th_th.dart

@ -132,7 +132,7 @@ const Map<String, String> thTH = {
"initializing": "กำลังเริ่มต้น...",
"bluetoothInitializationFailure": "การเริ่มต้นบริการบลูทูธล้มเหลว",
"checkingPermissions": "กำลังตรวจสอบสิทธิ์...",
"lackPermissions": "ขาดสิทธิ์บลูทูธ",
"lackPermissions": "ขาดสิทธิ์บลูทูธและต้องอนุญาตการเข้าถึงตำแหน่ง",
"searchingDevice": "กำลังค้นหาอุปกรณ์...",
"findConnectedDevice": "พบอุปกรณ์ที่เชื่อมต่อแล้ว",
"notFound": "ไม่พบอุปกรณ์บลูทูธที่เชื่อมต่อ",
@ -176,21 +176,9 @@ const Map<String, String> thTH = {
"healthConsultantInfo": "มีฟังก์ชันแชท AI เพิ่มเติม",
"conferenceAssistant": "ผู้ช่วยประชุมธุรกิจ",
"conferenceAssistantInfo": "บันทึกการประชุมแบบเรียลไทม์ แปลหลายภาษา",
"studyAssistant": "ผู้ช่วยเรียนภาษา",
"studyAssistantInfo": "แก้ไขการออกเสียง ฝึกพูดแบบเรียลไทม์",
"travelTranslator": "ผู้ช่วยแปลภาษาสำหรับการเดินทาง",
"travelTranslatorInfo": "แปลเสียงแบบเรียลไทม์ แนะนำสถานที่ท่องเที่ยว",
"beSearching": "กำลังค้นหา:",
"noAssistantFound": "ไม่พบผู้ช่วย AI ที่ตรงกัน",
"usageStats": "สถิติการใช้งาน",
"usageStatsInfo": "ดูสถิติการใช้งานของคุณ",
"scene": "สถานการณ์",
"youHaveSelected": "คุณได้เลือก:",
"newFunction": "ฟังก์ชันใหม่",
"youChoseTry": "คุณเลือกที่จะลอง",
"aiSinger": "โหมดนักร้อง AI",
"aiSingerInfo":
"ร้องเพลงใดก็ได้ด้วยเสียงของนักร้องที่คุณชื่นชอบ แม้แต่เพลงที่คุณแต่งเอง",
"popularFunction": "สถานการณ์ฟังก์ชันยอดนิยม",
"tryNow": "ลองเลย",
// 商务会议助手页
"startMeeting": "เริ่มการประชุม",
@ -206,8 +194,12 @@ const Map<String, String> thTH = {
'meetingTranscript': 'ข้อความถอดเสียงการประชุม',
// 设置页
"systemSettings": "การตั้งค่าระบบ",
"premiumMember": "สมาชิกระดับพรีเมียม",
"systemSettings": "การตั้งค่าระบบ", //系统设置
"vipRecharge": "การเติมเงินสมาชิกระดับพรีเมียม", //会员充值
"aiRecharge": "สมาชิกระดับพรีเมียม", //AI充值
"translationRecharge": "การเติมเงินการแปล", //翻译充值
"meetingAssistantRecharge": "การเติมเงินผู้ช่วยการประชุม", //会议助手充值
"cloudSync": "การเติมเงินการ đồng bộ hóaคลาวด์", //云端同步
"joinDevice": "อุปกรณ์ที่เชื่อมต่อ:",
"accountId": "ID บัญชี:",
"systemSetting": "การตั้งค่าระบบ",
@ -276,7 +268,7 @@ const Map<String, String> thTH = {
//Agent 模块
// agent View
"XiaoYan": "เสี่ยวเหยียน",
"Lily": "Lily",
"clearChatHistory": "ล้างประวัติการแชท",
"online": "ออนไลน์",
"inputMessage": "ป้อนข้อความ...",
@ -685,7 +677,7 @@ const Map<String, String> thTH = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "การจับคู่อุปกรณ์",
"connectYourDeepSoundHeadset": "เชื่อมต่อหูฟัง DeepSound ของคุณ",
"connectYourDeepSoundHeadset": "เชื่อมต่อหูฟัง Voitrans ของคุณ",
"bind": "ผูก",
"authorizeBind": "อนุญาตการผูก",
"enterCode": "กรุณาใส่รหัส",

35
lib/core/translations/language/tl_ph.dart

@ -138,7 +138,8 @@ const Map<String, String> tlPH = {
"bluetoothInitializationFailure":
"Nabigo ang pag-initialize ng serbisyo ng Bluetooth",
"checkingPermissions": "Sinusuri ang mga pahintulot...",
"lackPermissions": "Kulang sa mga pahintulot ng Bluetooth",
"lackPermissions":
"Kulang sa mga pahintulot ng Bluetooth at sumasang-ayon ka sa lokasyon",
"searchingDevice": "Naghahanap ng mga device...",
"findConnectedDevice": "Natagpuan ang konektadong device",
"notFound": "Walang natagpuang konektadong Bluetooth device",
@ -184,23 +185,9 @@ const Map<String, String> tlPH = {
"conferenceAssistant": "Business Meeting Assistant",
"conferenceAssistantInfo":
"Real-time na pagtatala ng mga minuto ng pulong, pagsasalin sa maraming wika",
"studyAssistant": "Language Learning Assistant",
"studyAssistantInfo":
"Pagwawasto ng bigkas, real-time na pagsasanay sa pagsasalita",
"travelTranslator": "Travel Translation Assistant",
"travelTranslatorInfo":
"Real-time na pagsasalin ng boses, pagpapakilala sa mga pasyalan",
"beSearching": "Naghahanap:",
"noAssistantFound": "Walang natagpuang katugmang AI assistant",
"usageStats": "Usage Statistics",
"usageStatsInfo": "View your usage statistics",
"scene": "Eksena",
"youHaveSelected": "Pinili mo ang:",
"newFunction": "Bagong Function",
"youChoseTry": "Pinili mong subukan",
"aiSinger": "AI Singer Mode",
"aiSingerInfo":
"Kantahin ang anumang kanta sa boses ng paborito mong mang-aawit, kahit na ang sarili mong mga likha",
"popularFunction": "Mga Sikat na Eksena ng Function",
"tryNow": "Subukan Ngayon",
// 商务会议助手页
"startMeeting": "Simulan ang Pulong",
@ -216,8 +203,12 @@ const Map<String, String> tlPH = {
'meetingTranscript': 'Transkripsyon ng Pulong',
// 设置页
"systemSettings": "Mga Setting ng System",
"premiumMember": "Premium na Miyembro",
"systemSettings": "Mga Setting ng System", //系统设置
"vipRecharge": "Pagsasalin ng Recharge ng Premium na Miyembro", //会员充值
"aiRecharge": "Premium na Miyembro", //AI充值
"translationRecharge": "Pagsasalin ng Recharge", //翻译充值
"meetingAssistantRecharge": "Pagsasalin ng Recharge ng Pulong", //会议助手充值
"cloudSync": "Pagsasalin ng Recharge ng Cloud", //云端同步
"joinDevice": "Konektadong device:",
"accountId": "Account ID:",
"systemSetting": "Setting ng System",
@ -289,7 +280,7 @@ const Map<String, String> tlPH = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Burahin ang Kasaysayan ng Chat",
"online": "Online",
"inputMessage": "Mag-type ng mensahe...",
@ -317,7 +308,7 @@ const Map<String, String> tlPH = {
"swipeUpForMore": "Mag-swipe pataas para sa higit pa",
// Agent controller
'welcomeMessage': 'Kumusta! Ako si **XiaoYan**, matutulungan kita sa:\n\n'
'welcomeMessage': 'Kumusta! Ako si **Lily**, matutulungan kita sa:\n\n'
'• Pagsagot sa mga tanong at pagbibigay ng impormasyon\n\n'
'• Real-time na pagsasalin ng boses\n\n'
'• Pagrekomenda ng musika at mga podcast\n\n'
@ -712,7 +703,7 @@ const Map<String, String> tlPH = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Pag-pair ng Device",
"connectYourDeepSoundHeadset": "Ikonekta ang iyong DeepSound Headset",
"connectYourDeepSoundHeadset": "Ikonekta ang iyong Voitrans Headset",
"bind": "I-bind",
"authorizeBind": "Pahintulutan ang pag-bind",
"enterCode": "Pakilagay ang code",

33
lib/core/translations/language/tr_tr.dart

@ -135,7 +135,7 @@ const Map<String, String> trTR = {
"initializing": "Başlatılıyor...",
"bluetoothInitializationFailure": "Bluetooth hizmeti başlatılamadı",
"checkingPermissions": "İzinler kontrol ediliyor...",
"lackPermissions": "Bluetooth izinleri eksik",
"lackPermissions": "Bluetooth izinleri eksik ve lokasyon erişimi gereklidir",
"searchingDevice": "Cihaz aranıyor...",
"findConnectedDevice": "Bağlı cihaz bulundu",
"notFound": "Bağlı Bluetooth cihazı bulunamadı",
@ -180,22 +180,9 @@ const Map<String, String> trTR = {
"conferenceAssistant": "İş Toplantısı Asistanı",
"conferenceAssistantInfo":
"Gerçek zamanlı toplantı tutanakları, çok dilli çeviri",
"studyAssistant": "Dil Öğrenme Asistanı",
"studyAssistantInfo": "Telaffuz düzeltme, gerçek zamanlı konuşma pratiği",
"travelTranslator": "Seyahat Çeviri Asistanı",
"travelTranslatorInfo":
"Gerçek zamanlı sesli çeviri, turistik yer tanıtımları",
"beSearching": "Aranıyor:",
"noAssistantFound": "İlgili yapay zeka asistanı bulunamadı",
"usageStats": "Kullanım İstatistikleri",
"usageStatsInfo": "Kullanım istatistiklerinizi görüntüleyin",
"scene": "Senaryo",
"youHaveSelected": "Seçtiniz:",
"newFunction": "Yeni Özellik",
"youChoseTry": "Denemeyi seçtiniz",
"aiSinger": "Yapay Zeka Şarkıcı Modu",
"aiSingerInfo":
"En sevdiğiniz sanatçının sesiyle herhangi bir şarkıyı, hatta kendi bestelerinizi söyleyin",
"popularFunction": "Popüler Özellik Senaryoları",
"tryNow": "Şimdi Dene",
// 商务会议助手页
"startMeeting": "Toplantıyı Başlat",
@ -211,8 +198,12 @@ const Map<String, String> trTR = {
'meetingTranscript': 'Toplantı Metni',
// 设置页
"systemSettings": "Sistem Ayarları",
"premiumMember": "Premium Üye",
"systemSettings": "Sistem Ayarları", //系统设置
"vipRecharge": "Premium Üye Recharge", //会员充值
"aiRecharge": "Premium Üye", //AI充值
"translationRecharge": "Çeviri Toplantı Recharge", //翻译充值
"meetingAssistantRecharge": "Toplantı Asistanı Recharge", //会议助手充值
"cloudSync": "Bulut Sincronizasyonu", //云端同步
"joinDevice": "Bağlı cihaz:",
"accountId": "Hesap Kimliği:",
"systemSetting": "Sistem Ayarları",
@ -283,7 +274,7 @@ const Map<String, String> trTR = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Sohbet Geçmişini Temizle",
"online": "Çevrimiçi",
"inputMessage": "Mesaj girin...",
@ -311,7 +302,7 @@ const Map<String, String> trTR = {
// Agent controller
'welcomeMessage':
'Merhaba! Ben **XiaoYan**, size şu konularda yardımcı olabilirim:\n\n'
'Merhaba! Ben **Lily**, size şu konularda yardımcı olabilirim:\n\n'
'• Soruları yanıtlamak ve bilgi sağlamak\n\n'
'• Gerçek zamanlı sesli çeviri\n\n'
'• Müzik ve podcast önermek\n\n'
@ -750,7 +741,7 @@ const Map<String, String> trTR = {
'retryAuthorization': 'Yetkilendirmeyi Yeniden Dene',
'pleaseGrantNecessaryPermissions': 'Lütfen gerekli izinleri verin',
'checkFailedRetry': 'Kontrol başarısız, lütfen tekrar deneyin',
'pleaseConnectDeepSoundDevice': 'Lütfen bir DeepSound cihazı bağlayın',
'pleaseConnectDeepSoundDevice': 'Lütfen bir Voitrans cihazı bağlayın',
'verificationFailedRetry': 'Doğrulama başarısız, lütfen tekrar deneyin',
'invalidDeviceAddress': 'Geçersiz cihaz adresi',
'bleDeviceAssociationFailed': 'BLE cihaz ilişkisi kurulamadı',

31
lib/core/translations/language/uk_ua.dart

@ -137,7 +137,8 @@ const Map<String, String> ukUA = {
"initializing": "Ініціалізація...",
"bluetoothInitializationFailure": "Помилка ініціалізації служби Bluetooth",
"checkingPermissions": "Перевірка дозволів...",
"lackPermissions": "Відсутні дозволи Bluetooth",
"lackPermissions":
"Відсутні дозволи Bluetooth і необхідно дозволити доступ до місцезнаходження",
"searchingDevice": "Пошук пристроїв...",
"findConnectedDevice": "Знайдено підключений пристрій",
"notFound": "Не знайдено підключеного пристрою Bluetooth",
@ -182,23 +183,9 @@ const Map<String, String> ukUA = {
"conferenceAssistant": "Помічник для ділових зустрічей",
"conferenceAssistantInfo":
"Запис протоколів у реальному часі, багатомовний переклад",
"studyAssistant": "Помічник у вивченні мов",
"studyAssistantInfo":
"Виправлення вимови, практика розмовної мови в реальному часі",
"travelTranslator": "Помічник-перекладач для подорожей",
"travelTranslatorInfo":
"Голосовий переклад у реальному часі, опис туристичних місць",
"beSearching": "Пошук:",
"noAssistantFound": "Не знайдено відповідного помічника AI",
"usageStats": "Статистика використання",
"usageStatsInfo": "Перегляньте статистику використання вашого пристрою",
"scene": "Сценарій",
"youHaveSelected": "Ви обрали:",
"newFunction": "Нова функція",
"youChoseTry": "Ви вирішили спробувати",
"aiSinger": "Режим AI співака",
"aiSingerInfo":
"Співайте будь-яку пісню голосом улюбленого співака, навіть пісні власного авторства",
"popularFunction": "Популярні функціональні сценарії",
"tryNow": "Спробувати зараз",
// 商务会议助手页
"startMeeting": "Почати зустріч",
@ -214,8 +201,12 @@ const Map<String, String> ukUA = {
'meetingTranscript': 'Транскрипт зустрічі',
// 设置页
"systemSettings": "Системні налаштування",
"premiumMember": "Преміум-учасник",
"systemSettings": "Системні налаштування", //系统设置
"vipRecharge": "Підписатися на премиум-членство", //会员充值
"aiRecharge": "Преміум-учасник", //AI充值
"translationRecharge": "Підписатися на переклад", //翻译充值
"meetingAssistantRecharge": "Підписатися на допомогу з зустрічю", //会议助手充值
"cloudSync": "Увімкнути синхронізацію в хмарі", //云端同步
"joinDevice": "Підключений пристрій:",
"accountId": "ID облікового запису:",
"systemSetting": "Системні налаштування",
@ -284,7 +275,7 @@ const Map<String, String> ukUA = {
//Agent 模块
// agent View
"XiaoYan": "СяоЯнь",
"Lily": "Lily",
"clearChatHistory": "Очистити історію чату",
"online": "В мережі",
"inputMessage": "Введіть повідомлення...",

34
lib/core/translations/language/vi_vn.dart

@ -133,7 +133,8 @@ const Map<String, String> viVN = {
"initializing": "Đang khởi tạo...",
"bluetoothInitializationFailure": "Khởi tạo dịch vụ Bluetooth thất bại",
"checkingPermissions": "Đang kiểm tra quyền...",
"lackPermissions": "Thiếu quyền Bluetooth",
"lackPermissions":
"Thiếu quyền Bluetooth và cần phải cấp quyền truy cập vị trí",
"searchingDevice": "Đang tìm kiếm thiết bị...",
"findConnectedDevice": "Đã tìm thấy thiết bị đã kết nối",
"notFound": "Không tìm thấy thiết bị Bluetooth đã kết nối",
@ -178,22 +179,9 @@ const Map<String, String> viVN = {
"conferenceAssistant": "Trợ lý hội nghị kinh doanh",
"conferenceAssistantInfo":
"Ghi lại biên bản họp thời gian thực, dịch đa ngôn ngữ",
"studyAssistant": "Trợ lý học ngôn ngữ",
"studyAssistantInfo": "Sửa lỗi phát âm, luyện nói thời gian thực",
"travelTranslator": "Trợ lý dịch thuật du lịch",
"travelTranslatorInfo":
"Dịch giọng nói thời gian thực, giới thiệu các điểm du lịch",
"beSearching": "Đang tìm kiếm:",
"noAssistantFound": "Không tìm thấy trợ lý AI tương ứng",
"usageStats": "Thống kê sử dụng",
"usageStatsInfo": "Xem thống kê sử dụng của bạn",
"scene": "Tình huống",
"youHaveSelected": "Bạn đã chọn:",
"newFunction": "Chức năng mới",
"youChoseTry": "Bạn đã chọn thử",
"aiSinger": "Chế độ ca sĩ AI",
"aiSingerInfo":
"Hát bất kỳ bài hát nào bằng giọng của ca sĩ bạn yêu thích, thậm chí cả bài hát do chính bạn sáng tác",
"popularFunction": "Các tình huống chức năng phổ biến",
"tryNow": "Thử ngay",
// 商务会议助手页
"startMeeting": "Bắt đầu cuộc họp",
@ -209,8 +197,12 @@ const Map<String, String> viVN = {
'meetingTranscript': 'Bản ghi cuộc họp',
// 设置页
"systemSettings": "Cài đặt hệ thống",
"premiumMember": "Thành viên Premium",
"systemSettings": "Cài đặt hệ thống", //系统设置
"vipRecharge": "Nạp lại dịch vụ Premium", //会员充值
"aiRecharge": "Thành viên Premium", //AI充值
"translationRecharge": "Nạp lại dịch vụ dịch", //翻译充值
"meetingAssistantRecharge": "Nạp lại dịch vụ hỗ trợ họp", //会议助手充值
"cloudSync": "Chuyển đổi đồng bộ hóa đám mây", //云端同步
"joinDevice": "Thiết bị đã kết nối:",
"accountId": "ID tài khoản:",
"systemSetting": "Cài đặt hệ thống",
@ -279,7 +271,7 @@ const Map<String, String> viVN = {
//Agent 模块
// agent View
"XiaoYan": "XiaoYan",
"Lily": "Lily",
"clearChatHistory": "Xóa lịch sử trò chuyện",
"online": "Trực tuyến",
"inputMessage": "Nhập tin nhắn...",
@ -306,7 +298,7 @@ const Map<String, String> viVN = {
"swipeUpForMore": "Vuốt lên để xem thêm",
// Agent controller
'welcomeMessage': 'Chào bạn! Tôi là **XiaoYan**, tôi có thể giúp bạn:\n\n'
'welcomeMessage': 'Chào bạn! Tôi là **Lily**, tôi có thể giúp bạn:\n\n'
'• Trả lời câu hỏi và cung cấp thông tin\n\n'
'• Dịch giọng nói thời gian thực\n\n'
'• Đề xuất nhạc và podcast\n\n'
@ -692,7 +684,7 @@ const Map<String, String> viVN = {
// 配对模块
// 配对页面 (pairing_view.dart & pairing_view_new.dart)
"devicePairing": "Ghép nối thiết bị",
"connectYourDeepSoundHeadset": "Kết nối tai nghe DeepSound của bạn",
"connectYourDeepSoundHeadset": "Kết nối tai nghe Voitrans của bạn",
"bind": "Liên kết",
"authorizeBind": "Ủy quyền liên kết",
"enterCode": "Vui lòng nhập mã",

307
lib/core/translations/language/zh_cn.dart

@ -132,7 +132,7 @@ const Map<String, String> zhCN = {
"initializing": "正在初始化...",
"bluetoothInitializationFailure": "蓝牙服务初始化失败",
"checkingPermissions": "正在检查权限...",
"lackPermissions": "缺少蓝牙权限",
"lackPermissions": "开启蓝牙和位置权限,才能发现并连接附近的设备",
"searchingDevice": "正在搜索设备...",
"findConnectedDevice": "找到已连接的设备",
"notFound": "未找到已连接的蓝牙设备",
@ -162,7 +162,7 @@ const Map<String, String> zhCN = {
"exploreSlogan1": "智能陪伴,无限可能",
"exploreSlogan2": "智能眼镜,无限可能",
"exploreAi": "探索Voitrans提供的AI功能",
"aiFunction": "AI功能",
"aiFunction": "AI助手",
"allRoundAssistant": "全能助理",
"allRoundAssistantInfo": "帮你解决各类问题",
"simultaneousTranslation": "同声翻译",
@ -176,20 +176,197 @@ const Map<String, String> zhCN = {
"healthConsultantInfo": "提供更多AI聊天功能",
"conferenceAssistant": "商务会议助手",
"conferenceAssistantInfo": "实时记录会议纪要,多语言翻译",
"studyAssistant": "语言学习助手",
"studyAssistantInfo": "发音纠正,实时练习口语",
"travelTranslator": "旅行翻译助手",
"travelTranslatorInfo": "实时语音翻译,旅游景点介绍",
"beSearching": "正在搜索:",
"noAssistantFound": "未找到对应的AI助手",
"usageStats": "用量统计",
"usageStatsInfo": "查看您的使用统计数据",
"scene": "场景",
"youHaveSelected": "您选择了:",
"newFunction": "新功能",
"youChoseTry": "您选择了尝试",
"aiSinger": "AI歌手模式",
"aiSingerInfo": "用你喜欢的歌手声音演唱任何歌曲,甚至是你自己创作的歌曲",
"popularFunction": "热门功能场景",
"tryNow": "立即尝试",
// 用量统计模块
"aiChat": "AI聊天",
"translationStats": "翻译统计",
"meetingStats": "会议统计",
"today": "今日",
"thisWeek": "本周",
"thisMonth": "本月",
"history": "历史",
"currentSessionStats": "当前会话统计",
"translationCount": "翻译次数",
"sessionDuration": "会话时长",
"characters": "字符数",
"recordingDuration": "录音时长",
"totalApiCalls": "总调用次数",
"sessionCount": "会话数量",
"totalCharacters": "总字符数",
"apiCallStats": "API调用统计",
"translationApi": "翻译API",
"asr": "语音识别",
"tts": "语音合成",
//"aiSummary": "AI摘要",
"dataVolumeStats": "数据量统计",
"sourceTextCharacters": "源文本字符",
"ttsTextCharacters": "TTS文本字符",
"effectiveAudioDuration": "有效音频时长",
"totalSessionDuration": "总会话时长",
"costStats": "成本统计",
"estimatedCost": "预估成本",
"dailyCostThreshold": "日成本预警阈值",
"monthlyCostThreshold": "月成本预警阈值",
"usageBehaviorStats": "使用行为统计",
"mostUsedLanguagePair": "最常用语言对",
"mostUsedMode": "最常用模式",
"asrApiCalls": "ASR调用次数",
"totalAudioDuration": "音频总时长",
"audioFileSize": "音频文件大小",
"transcriptBytes": "转写字节",
// 通知文案
"loadFailed": "加载失败",
"statsLoadFailedTryLater": "统计数据加载失败,请稍后重试",
"cleanupComplete": "清理完成",
"cleanedOldData": "已清理90天前的过期数据",
"exportFeature": "导出功能",
"exportInDevelopment": "数据导出功能正在开发中",
// 商品页面(AI/翻译/会议)
'availablePackages': '可购买套餐',
'remainingQuota': '剩余额度',
'totalQuota': '总额度',
'remaining': '剩余',
'featureDescription': '功能说明',
// AI 功能卡片
'musicAndRecommendation': '听歌与推荐',
'navigationAndRoutes': '导航与路线',
'nearbySearch': '附近搜索',
'newsInformation': '新闻资讯',
'communicationAssistant': '通讯助手',
// 翻译功能卡片
'realtimeTranscription': '实时同传',
// 'textTranslation' 已存在
'sceneLexicon': '场景词库',
'subtitleDisplay': '字幕显示',
// 会议功能卡片
'meetingRecording': '会议记录',
'transcriptionAndSummary': '转写与总结',
'keywordSearch': '关键词检索',
'collaborationSharing': '协同分享',
// 商品名称(按ID)
'ai_001_name': 'AI基础 100 次',
'ai_002_name': 'AI基础 500 次',
'ai_003_name': 'AI基础 1000 次',
'meet_001_name': '会议基础 100 次',
'meet_002_name': '会议基础 500 次',
'meet_003_name': '会议基础 1000 次',
'trans_001_name': '翻译基础 100 次',
'trans_002_name': '翻译基础 500 次',
'trans_003_name': '翻译基础 1000 次',
// 商品描述(按ID)
'ai_001_desc': '含 100 次使用,覆盖核心 AI 功能',
'ai_002_desc': '含 500 次使用,覆盖核心 AI 功能',
'ai_003_desc': '含 1000 次使用,覆盖核心 AI 功能',
'meet_001_desc': '含 100 次会议录音/转写',
'meet_002_desc': '含 500 次会议录音/转写',
'meet_003_desc': '含 1000 次会议录音/转写',
'trans_001_desc': '含 100 次翻译(语音/文本)',
'trans_002_desc': '含 500 次翻译(语音/文本)',
'trans_003_desc': '含 1000 次翻译(语音/文本)',
// 商品页通用页脚
'appNameProvider': '应用名称:Voitrans · 服务提供:Voitrans',
'iapCustomerServiceQQLabel': '内购商品专属客服QQ:@qq',
'copyrightVoitrans': '© 2025 Voitrans Technologies',
// 会议商品页描述
'meetingHeaderDesc1': '录音转写、关键词检索与自动总结,提升会议效率。',
'meetingHeaderDesc2': '适用于商务会议、课堂笔记、访谈纪要等场景。',
'meetingAutoRecording': '自动录音与分段',
'meetingSpeakerTagging': '讲话人标注',
'meetingLongAudioTranscription': '长音频转写',
'meetingKeyPointSummary': '关键要点提炼',
'meetingTopicNameSearch': '按主题/人名检索',
'meetingTimelineJump': '时间线跳转',
'meetingExportSummary': '导出纪要',
'meetingMultiPlatformShare': '多平台分享',
'meetingDisclaimer': '建议在安静环境使用,效果受麦克风与网络影响,具体以实际表现为准。',
// 同传/翻译商品页描述
'transHeaderDesc1': '多语种实时同传与文本翻译,低延时语音播报。',
'transHeaderDesc2': '适用于出行、商务、演讲与教学等场景。',
'translateZhEn': '中英互译',
'lowLatencyVoiceBroadcast': '低延时语音播报',
'multiLangTextTranslation': '多语种文本翻译',
'termOptimizationContextPreserve': '术语优化与语境保持',
'lexiconTourBusinessLife': '旅游/商务/生活词库',
'personalVocabularyMemory': '专属词汇记忆',
'conversationSubtitleLargeText': '对话字幕/大字模式',
'colorHighContrast': '颜色高对比度',
'transDisclaimer': '翻译效果受麦克风、网络时延与环境噪声影响,具体以实际表现为准。',
// AI 商品页描述
'aiHeaderDesc1': '更长对话额度、更多工具调用、更强上下文长度支持。',
'aiHeaderDesc2': '适用于智能体问答、总结分析、任务执行等场景。',
'musicSearchPlaybackControl': '检索曲库、播放控制',
'smartPlaylistAndSimilarRecommendations': '智能推荐歌单与相似歌曲',
'routePlanningAndCongestionAvoidance': '路线规划与拥堵规避',
'voiceBroadcastAndWaypoints': '语音播报与途径点设置',
'realTimeWeatherForecast': '实时天气与预报',
'clothingAdviceAndTravelReminders': '穿衣建议与出行提醒',
'poiSearchFoodGasParking': '餐饮/加油/停车等地点检索',
'ratingsHoursAndDirectRoutes': '评分、营业时间与路线直达',
'hotNewsAndTopicOverview': '热点快讯与专题速览',
'longArticleSummariesAndKeyPoints': '长文总结与要点提炼',
'helpCallAndSMS': '帮忙拨打电话与发短信',
'templatedMessagesAndScheduleReminders': '模板消息与日程提醒',
'aiDisclaimer': '以上功能受设备权限、服务可用性与网络状况影响,具体以实际表现为准。',
// 会员商品页
'benefitsOverview': '权益总览',
'higherQuota': '更高使用额度',
'lowerUnitPrice': '更低单价',
'priorityService': '优先服务',
'exclusiveSupportChannel': '专属客服通道',
'fastResponse': '问题快速响应',
'eventsAndDiscounts': '活动与折扣',
'memberExclusiveEvents': '会员专属活动',
'longTermDiscountPlan': '长期优惠计划',
'generalPrivileges': '通用特权',
'earlyAccessNewFeatures': '新功能优先体验',
'crossDeviceSync': '跨设备同步',
'vipDisclaimer': '具体权益以实际套餐说明为准,可能随版本迭代调整。',
// 新手引导 / Onboarding
'skip': '跳过',
'next': '下一步',
'sayLilyHint': '对着麦克风说:“Lily Lily”',
'imHere': '我在呢~',
'guideWelcomeWakeAI': '欢迎使用Voitrans!首先,让我们唤醒你的专属 AI—— Lily',
'aiReplyCompleted': 'Lily已经完成了回答!',
'aiThinking': 'Lily正在思考中~',
'guideAwakenSuccess': '太棒了!你已成功唤醒Lily,接下来试试让它帮你做件事吧',
'confirmInput': '确定输入',
'guideClickSendPrefix': '点击发送,',
// AI 引导步骤
'guideWeatherStart': '对Lily说:“今天天气怎么样”',
'guideWeatherInput': '今天天气怎么样',
'guideWeatherSend': 'Lily会为你实时为你播报天气',
'guideWeatherEnd': 'Lily能实时为你播报天气,试试其他指令吧',
'guideMusicStart': '对Lily说:“请播放一组摇滚乐”',
'guideMusicInput': '请播放一组摇滚乐',
'guideMusicSend': 'Lily会为你搜寻到一组音乐',
'guideMusicEnd': 'Lily已成功为您搜寻到一组音乐,试试其他指令吧',
'guideNavStart': '对Lily说:“导航到深圳机场”',
'guideNavInput': '导航到深圳机场',
'guideNavSend': 'Lily会为你规划路线',
'guideNavEnd': 'Lily已成功为您导航到深圳机场,试试其他指令吧',
'guideMeetingStart': '对Lily说:“明天下午3点创建会议提醒”',
'guideMeetingInput': '明天下午3点创建会议提醒',
'guideMeetingSend': 'Lily会为你创建会议提醒',
'guideMeetingEnd': 'Lily已成功为您创建会议提醒,试试其他指令吧',
'guidePhoneStart': '对Lily说:“拨打妈妈的电话”',
'guidePhoneInput': '拨打妈妈的电话',
'guidePhoneSend': 'Lily会为你拨打电话',
'guidePhoneEnd': 'Lily已成功为您拨打电话,试试其他指令吧',
'guideSmsStart': '对Lily说:“给爸爸发短信说晚上回家吃饭”',
'guideSmsInput': '给爸爸发短信说晚上回家吃饭',
'guideSmsSend': 'Lily会为你发送短信',
'guideSmsEnd': '短信已发送,语音操控更便捷',
// 商务会议助手页
"startMeeting": "开始会议",
@ -415,7 +592,14 @@ const Map<String, String> zhCN = {
// 设置页
"systemSettings": "系统设置",
"premiumMember": "高级会员",
"vipRecharge": "会员充值",
"aiRecharge": "AI充值",
"translationRecharge": "翻译充值",
"meetingAssistantRecharge": "会议充值",
"cloudSync": "云端同步",
"memberService": "会员服务",
"bindRewardTitle": "奖励",
"bindRewardSimpleDesc": "首次绑定设备奖励已下发,点击确定关闭即可",
"joinDevice": "已连接设备:",
"accountId": "账号ID:",
"systemSetting": "系统设置",
@ -488,7 +672,7 @@ const Map<String, String> zhCN = {
//Agent 模块
// agent View
"XiaoYan": "小言",
"Lily": "Lily",
"clearChatHistory": "清空聊天记录",
"online": "在线",
"inputMessage": "输入消息...",
@ -529,7 +713,7 @@ const Map<String, String> zhCN = {
"nearbyFood": "附近有哪些美食?", // 美食
// Agent controller
'welcomeMessage': '你好!我是**小言**,我能帮你:\n\n'
'welcomeMessage': '你好!我是**Lily**,我能帮你:\n\n'
'• 答问题和提供信息\n\n'
'• 实时语音翻译\n\n'
'• 推荐音乐和播客\n\n'
@ -610,6 +794,17 @@ const Map<String, String> zhCN = {
"friday": "周五",
"saturday": "周六",
"sunday": "周日",
// 首次绑定奖励弹窗(英文文案,保持一致性)
"firstBindRewardTitle": "Welcome Reward",
"firstBindRewardDesc": "You've received binding rewards.",
"vipLevelLabel": "VIP Level:",
"expiryLabel": "到期时间:",
"notActivated": "未激活",
"aiChatCreditsLabel": "AI Chat Credits:",
"translationCreditsLabel": "Translation Credits:",
"meetingCreditsLabel": "Meeting Credits:",
"ok": "OK",
// 天气描述
"sunny": "晴",
"partlyCloudy": "少云",
@ -910,22 +1105,76 @@ const Map<String, String> zhCN = {
"phoneUser": "手机用户",
"selectSourceLanguage": "选择源语言",
"selectTargetLanguage": "选择目标语言",
"me": "我", //我
"counterPart": "对方", //对方
"me": "我",
"counterPart": "对方",
"bluetoothCallStateError": "请确保蓝牙耳机已连接到手机并处于通话状态",
// 通用对话按钮与选项(用于统一语言选择弹窗等)
// 以下翻译键的中文文本内容如注释所示
"autoDetect": "自动检测", // 自动检测
// 文本翻译与语种检测
"languageDetectionFailed": "语言检测失败",
"translationFailed": "翻译失败",
"pleaseInputText": "请输入文本",
"textTooLong": "文本过长,最多5000字符",
// 翻译历史页 (translation_history_view.dart)
// 翻译历史页
"noTranslationHistory": "暂无历史记录",
"historyRecords": "历史记录",
"clearResults": "清空结果",
"clearHistory": "清除历史记录",
"clearHistoryConfirm": "确定要清除所有翻译历史记录吗?此操作无法撤销。",
"unknownLanguage": "未知语言",
"deleteSessionRecord": "删除会话记录",
"deleteSessionConfirm": "确定要删除该会话的所有翻译记录吗?此操作无法撤销。",
// 翻译录音文件列表页 (translation_list_view.dart)
// 图片翻译模块(Picture Translation)
"selectImageSource": "选择图片来源",
"imagePreview": "图片预览",
"translationResult": "翻译结果",
"recognitionResult": "识别结果",
"translatedImagePreview": "翻译后的图片预览",
"translatedImageLoadFailed": "翻译图片加载失败",
"pleaseSelectImage": "请选择图片",
"imageLoadFailed": "图片加载失败",
"imageQuality": "图片质量",
"maxSize": "最大尺寸",
"close": "关闭",
"setImageQuality": "设置图片质量",
"currentQuality": "当前质量: @value%",
"setMaxSize": "设置最大尺寸",
"currentMaxSize": "当前: @pxpx",
"waitingForAction": "等待操作",
"pleaseSelectImageToStart": "请选择图片开始翻译",
"chooseImage": "选择图片",
"openingCamera": "正在打开相机...",
"openingPhotoAlbum": "正在打开相册...",
"cancelled": "已取消",
"userCancelledSelection": "用户取消了选择",
"translatingImage": "翻译图片",
"callingImageTranslateService": "正在调用图片翻译服务...",
"savingRecord": "保存记录",
"savingTranslationResult": "正在保存翻译结果...",
"translationCompleted": "翻译完成",
"allStepsCompleted": "所有步骤已完成",
"processingFailed": "处理失败",
"imageProcessingOrTranslationFailed": "图片处理或翻译失败,请重试。\n错误信息: {error}",
"imageTooLarge": "图片大小超过4MB限制",
"imageTooLargeHint": "图片大小超过4MB限制,请降低质量或尺寸后重试",
"emptyTranslationResult": "图片翻译接口返回空结果",
"imageTranslationFailedTryLater": "图片翻译失败,可能的原因:网络异常或接口限流,请稍后重试",
"imageTranslationApiException": "图片翻译接口调用异常,请检查网络后重试",
"permissionRequired": "权限需求",
"cameraPermissionRequired": "需要相机权限才能拍照",
"photoAlbumPermissionRequired": "需要相册权限才能选择图片",
"translationDetails": "翻译详情",
"originalImage": "原图片",
"sourceLanguage": "源语言",
"targetLanguage": "目标语言",
"translationTime": "翻译时间",
"shareInDevelopment": "分享功能开发中",
// 翻译录音文件列表页
"translateAudioFiles": "翻译录音文件",
"noAudioFiles": "暂无音频文件",
"calculating": "计算中...",
@ -968,7 +1217,7 @@ const Map<String, String> zhCN = {
"autoInputCode": "自动输入代码",
"skipBinding": "跳过绑定",
"rescan": "重新扫描",
"skip": "跳过",
"verifyingDevice": "正在验证设备...",
"confirmBinding": "确认绑定",
"associatingDevice": "正在关联设备...",
@ -1115,4 +1364,16 @@ const Map<String, String> zhCN = {
"justNow": "刚刚",
"minutesAgo": "@minutes分钟前",
"yesterday": "昨天",
// 时间扩展(图片翻译模块使用)
"daysAgo": "@days天前",
"hoursAgo": "@hours小时前",
//补充
"insufficientIntegral": "积分不足",
//余额不足弹窗
"insufficientBalanceDesc": "余额不足,请前往对应充值界面进行充值",
"recharge": "前往充值",
// 会员到期提示
"aiMemberExpiredDesc": "AI会员已到期,请前往会员充值续费",
};

153
lib/core/translations/language/zh_hk.dart

@ -131,7 +131,7 @@ const Map<String, String> zhHK = {
"initializing": "正在初始化...",
"bluetoothInitializationFailure": "藍牙服務初始化失敗",
"checkingPermissions": "正在檢查權限...",
"lackPermissions": "缺少藍牙權限",
"lackPermissions": "開啟藍牙和位置權限,才能發現並連接附近的設備",
"searchingDevice": "正在搜尋設備...",
"findConnectedDevice": "找到已連接的設備",
"notFound": "未找到已連接的藍牙設備",
@ -161,7 +161,7 @@ const Map<String, String> zhHK = {
"exploreSlogan1": "智能陪伴,無限可能",
"exploreSlogan2": "智能眼鏡,無限可能",
"exploreAi": "探索Voitrans提供的AI功能",
"aiFunction": "AI功能",
"aiFunction": "AI助手",
"allRoundAssistant": "全能助理",
"allRoundAssistantInfo": "幫你解決各類問題",
"simultaneousTranslation": "同聲翻譯",
@ -175,20 +175,30 @@ const Map<String, String> zhHK = {
"healthConsultantInfo": "提供更多AI聊天功能",
"conferenceAssistant": "商務會議助手",
"conferenceAssistantInfo": "實時記錄會議紀要,多語言翻譯",
"studyAssistant": "語言學習助手",
"studyAssistantInfo": "發音糾正,實時練習口語",
"travelTranslator": "旅行翻譯助手",
"travelTranslatorInfo": "實時語音翻譯,旅遊景點介紹",
"beSearching": "正在搜尋:",
"noAssistantFound": "未找到對應的AI助手",
"usageStats": "用量統計",
"usageStatsInfo": "查看您的使用統計數據",
"scene": "場景",
"youHaveSelected": "您選擇了:",
"newFunction": "新功能",
"youChoseTry": "您選擇了嘗試",
"aiSinger": "AI歌手模式",
"aiSingerInfo": "用你喜歡的歌手聲音演唱任何歌曲,甚至是你自己創作的歌曲",
"popularFunction": "熱門功能場景",
"tryNow": "立即嘗試",
// 商品名稱(按ID)
'ai_001_name': 'AI基礎 100 次',
'ai_002_name': 'AI基礎 500 次',
'ai_003_name': 'AI基礎 1000 次',
'meet_001_name': '會議基礎 100 次',
'meet_002_name': '會議基礎 500 次',
'meet_003_name': '會議基礎 1000 次',
'trans_001_name': '翻譯基礎 100 次',
'trans_002_name': '翻譯基礎 500 次',
'trans_003_name': '翻譯基礎 1000 次',
// 商品描述(按ID)
'ai_001_desc': '含 100 次使用,涵蓋核心 AI 功能',
'ai_002_desc': '含 500 次使用,涵蓋核心 AI 功能',
'ai_003_desc': '含 1000 次使用,涵蓋核心 AI 功能',
'meet_001_desc': '含 100 次會議錄音/轉寫',
'meet_002_desc': '含 500 次會議錄音/轉寫',
'meet_003_desc': '含 1000 次會議錄音/轉寫',
'trans_001_desc': '含 100 次翻譯(語音/文本)',
'trans_002_desc': '含 500 次翻譯(語音/文本)',
'trans_003_desc': '含 1000 次翻譯(語音/文本)',
// 商務會議助手頁
"startMeeting": "開始會議",
@ -204,8 +214,12 @@ const Map<String, String> zhHK = {
'meetingTranscript': '會議原文',
// 設定頁
"systemSettings": "系統設定",
"premiumMember": "高級會員",
"systemSettings": "系統設定", //系统设置
"vipRecharge": "高級會員充值", //会员充值
"aiRecharge": "AI充值", //AI充值
"translationRecharge": "翻譯充值", //翻译充值
"meetingAssistantRecharge": "會議充值", //会议充值
"cloudSync": "雲端同步", //云端同步
"joinDevice": "已連接設備:",
"accountId": "帳號ID:",
"systemSetting": "系統設定",
@ -270,7 +284,7 @@ const Map<String, String> zhHK = {
//Agent 模塊
// agent View
"XiaoYan": "小言",
"Lily": "Lily",
"clearChatHistory": "清空聊天記錄",
"online": "在線",
"inputMessage": "輸入訊息...",
@ -299,7 +313,7 @@ const Map<String, String> zhHK = {
"voice_interrupt": "语音打断", // 语音打断
// Agent controller
'welcomeMessage': '你好!我是**小言**,我能幫你:\n\n'
'welcomeMessage': '你好!我是**Lily**,我能幫你:\n\n'
'• 回答問題和提供資訊\n\n'
'• 實時語音翻譯\n\n'
'• 推薦音樂和播客\n\n'
@ -787,4 +801,105 @@ const Map<String, String> zhHK = {
"乌尔都语": "烏爾都語",
"波斯语": "波斯語",
"斯瓦希里语": "斯瓦希里語",
// Guide overlay keys (placeholders in English)
"sayLilyHint": "Say \"Lily Lily\" to the mic",
"imHere": "I’m here~",
"guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Lily”.",
"aiReplyCompleted": "Lily has finished the reply!",
"aiThinking": "Lily is thinking…",
"guideAwakenSuccess": "Great! Lily is awake—ask it to help.",
"confirmInput": "Confirm Input",
"guideClickSendPrefix": "Tap send, ",
"guideWeatherStart": "Tell Lily: “What’s the weather today?”",
"guideWeatherInput": "What’s the weather today?",
"guideWeatherSend": "Lily will report the weather in real time",
"guideWeatherEnd": "Lily can report weather live—try other commands",
"guideMusicStart": "Tell Lily: “Play some rock music”",
"guideMusicInput": "Play some rock music",
"guideMusicSend": "Lily will find music for you",
"guideMusicEnd": "Lily found music—try other commands",
"guideNavStart": "Tell Lily: “Navigate to Shenzhen Airport”",
"guideNavInput": "Navigate to Shenzhen Airport",
"guideNavSend": "Lily will plan the route",
"guideNavEnd": "Navigation set—try other commands",
"guideMeetingStart":
"Tell Lily: “Create a meeting reminder for 3pm tomorrow”",
"guideMeetingInput": "Create a meeting reminder for 3pm tomorrow",
"guideMeetingSend": "Lily will create a meeting reminder",
"guideMeetingEnd": "Reminder created—try other commands",
"guidePhoneStart": "Tell Lily: “Call Mom”",
"guidePhoneInput": "Call Mom",
"guidePhoneSend": "Lily will make the call",
"guidePhoneEnd": "Call placed—try other commands",
"guideSmsStart": "Tell Lily: “Send Dad a text: I’ll be home for dinner”",
"guideSmsInput": "Text Dad: I’ll be home for dinner",
"guideSmsSend": "Lily will send the message",
"guideSmsEnd": "Message sent—voice control is convenient",
// 商品页通用页脚
'appNameProvider': '應用名稱:Voitrans · 服務提供:Voitrans',
'iapCustomerServiceQQLabel': '內购商品专属客服QQ:@qq',
'copyrightVoitrans': '© 2025 Voitrans Technologies',
// Meeting goods page (placeholders)
'meetingHeaderDesc1': '錄音轉寫、關鍵詞檢索與自動總結,提升會議效率。',
'meetingHeaderDesc2': '適用於商務會議、課堂筆記、訪談紀要等場景。',
'meetingAutoRecording': '自動錄音與分段',
'meetingSpeakerTagging': '講話人標注',
'meetingLongAudioTranscription': '長音頻轉寫',
'meetingKeyPointSummary': '關鍵要點提煉',
'meetingTopicNameSearch': '按主題/人名檢索',
'meetingTimelineJump': '時間線跳轉',
'meetingExportSummary': '導出紀要',
'meetingMultiPlatformShare': '多平台分享',
'meetingDisclaimer': '建議在安靜環境使用,效果受麥克風與網絡影響,具體以實際表現為準。',
// Translation goods page (placeholders)
'transHeaderDesc1': '多語種實時同傳與文本翻譯,低延時語音播報。',
'transHeaderDesc2': '適用於出行、商務、演講與教學等場景。',
'translateZhEn': '中英互譯',
'lowLatencyVoiceBroadcast': '低延時語音播報',
'multiLangTextTranslation': '多語種文本翻譯',
'termOptimizationContextPreserve': '術語優化與語境保持',
'lexiconTourBusinessLife': '旅遊/商務/生活詞庫',
'personalVocabularyMemory': '專屬詞彙記憶',
'conversationSubtitleLargeText': '對話字幕/大字模式',
'colorHighContrast': '顏色高對比度',
'transDisclaimer': '翻譯效果受麥克風、網絡時延與環境噪聲影響,具體以實際表現為準。',
// AI 商品頁描述(佔位)
'aiHeaderDesc1': '更長對話額度、更多工具調用、更強上下文長度支持。',
'aiHeaderDesc2': '適用於智能體問答、總結分析、任務執行等場景。',
'musicSearchPlaybackControl': '檢索曲庫、播放控制',
'smartPlaylistAndSimilarRecommendations': '智能推薦歌單與相似歌曲',
'routePlanningAndCongestionAvoidance': '路線規劃與擁堵規避',
'voiceBroadcastAndWaypoints': '語音播報與途徑點設置',
'realTimeWeatherForecast': '實時天氣與預報',
'clothingAdviceAndTravelReminders': '穿衣建議與出行提醒',
'poiSearchFoodGasParking': '餐飲/加油/停車等地點檢索',
'ratingsHoursAndDirectRoutes': '評分、營業時間與路線直達',
'hotNewsAndTopicOverview': '熱點快訊與專題速覽',
'longArticleSummariesAndKeyPoints': '長文總結與要點提煉',
'helpCallAndSMS': '幫忙撥打電話與發短信',
'templatedMessagesAndScheduleReminders': '模板消息與日程提醒',
'aiDisclaimer': '以上功能受設備權限、服務可用性與網絡狀況影響,具體以實際表現為準。',
// VIP goods page (placeholders)
'benefitsOverview': '權益總覽',
'higherQuota': '更高使用額度',
'lowerUnitPrice': '更低單價',
'priorityService': '優先服務',
'exclusiveSupportChannel': '專屬客服通道',
'fastResponse': '問題快速響應',
'eventsAndDiscounts': '活動與折扣',
'memberExclusiveEvents': '會員專屬活動',
'longTermDiscountPlan': '長期優惠計劃',
'generalPrivileges': '通用特權',
'earlyAccessNewFeatures': '新功能優先體驗',
'crossDeviceSync': '跨設備同步',
'vipDisclaimer': '具體權益以實際套餐說明為準,可能隨版本迭代調整。',
//余额不足弹窗
"insufficientBalanceDesc": "餘額不足,請前往對應充值界面進行充值",
"recharge": "去充值",
};

17
lib/core/widgets/intro_overlay_builder.dart

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_intro/flutter_intro.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:lottie/lottie.dart';
class IntroOverlayBuilder {
@ -19,7 +20,7 @@ class IntroOverlayBuilder {
static Widget homeBuilder(
StepWidgetParams params,
bool isWakeup, {
String title = '对着麦克风说:“小言小言”',
String title = 'sayLilyHint',
Function? onNext,
}) {
return Column(
@ -29,7 +30,7 @@ class IntroOverlayBuilder {
margin: EdgeInsets.only(top: ScreenUtil().statusBarHeight),
alignment: Alignment.centerRight,
child: _button(
'跳过',
'skip'.tr,
() {
params.onFinish();
},
@ -47,7 +48,7 @@ class IntroOverlayBuilder {
Padding(
padding: EdgeInsets.only(bottom: 10.w),
child: Text(
isWakeup ? '我在呢~' : title,
isWakeup ? 'imHere'.tr : title.tr,
style: TextStyle(
fontSize: 15.sp,
color: Colors.white,
@ -57,7 +58,7 @@ class IntroOverlayBuilder {
),
if (onNext != null)
_button(
'下一步',
'next'.tr,
() {
params.onNext!();
onNext();
@ -70,7 +71,7 @@ class IntroOverlayBuilder {
static Widget aiBuilder(
StepWidgetParams params,
String text, {
String buttonText = '下一步',
String buttonText = 'next',
bool alignment = true,
Function? onNext,
Function? onFinish,
@ -92,7 +93,7 @@ class IntroOverlayBuilder {
margin: EdgeInsets.only(top: ScreenUtil().statusBarHeight),
alignment: Alignment.centerRight,
child: _button(
'跳过',
'skip'.tr,
() {
params.onFinish();
},
@ -125,7 +126,7 @@ class IntroOverlayBuilder {
Padding(
padding: EdgeInsets.only(top: 10.w, left: 3, right: 3),
child: _button(
buttonText,
buttonText.tr,
() {
params.onNext!();
onNext();
@ -136,7 +137,7 @@ class IntroOverlayBuilder {
Padding(
padding: EdgeInsets.only(top: 10.w, left: 3, right: 3),
child: _button(
buttonText,
buttonText.tr,
() {
params.onFinish();
onFinish();

2
lib/data/models/appconfig_model.dart

@ -79,6 +79,7 @@ class DBProduct {
final String? productimage;
final String scanuuid;
final String? version;
bool? isforceupdate;
final bool? iscontinuouschat;
final String? updatedescription;
final String? updatepackageaddress;
@ -91,6 +92,7 @@ class DBProduct {
required this.productimage,
required this.scanuuid,
required this.version,
required this.isforceupdate, //该产品固件版本是否强制更新
required this.iscontinuouschat,
required this.updatedescription,
required this.updatepackageaddress,

2
lib/data/models/appconfig_model.g.dart

@ -79,6 +79,7 @@ DBProduct _$DBProductFromJson(Map<String, dynamic> json) => DBProduct(
productimage: json['productimage'] as String?,
scanuuid: json['scanuuid'] as String,
version: json['version'] as String?,
isforceupdate: json['isforceupdate'] as bool?,
iscontinuouschat: json['iscontinuouschat'] as bool?,
updatedescription: json['updatedescription'] as String?,
updatepackageaddress: json['updatepackageaddress'] as String?,
@ -91,6 +92,7 @@ Map<String, dynamic> _$DBProductToJson(DBProduct instance) => <String, dynamic>{
'productimage': instance.productimage,
'scanuuid': instance.scanuuid,
'version': instance.version,
'isforceupdate': instance.isforceupdate,
'iscontinuouschat': instance.iscontinuouschat,
'devicename': instance.devicename,
'updatedescription': instance.updatedescription,

10
lib/data/models/channel_app_model.dart

@ -69,12 +69,22 @@ class AppInfo {
@JsonKey(name: 'tourists')
final bool tourists;
/// 是否允许跳过设备绑定
@JsonKey(name: 'allowskipdevicebinding')
final bool allowskipdevicebinding;
/// 支付渠道列表
@JsonKey(name: 'Paychannels')
final String? paychannels;
const AppInfo({
this.address,
required this.channel,
required this.description,
required this.version,
this.tourists = false,
this.allowskipdevicebinding = false,
required this.paychannels,
});
factory AppInfo.fromJson(Map<String, dynamic> json) =>

4
lib/data/models/channel_app_model.g.dart

@ -38,6 +38,8 @@ AppInfo _$AppInfoFromJson(Map<String, dynamic> json) => AppInfo(
description: json['description'] as String,
version: json['version'] as String,
tourists: json['tourists'] as bool? ?? false,
allowskipdevicebinding: json['allowskipdevicebinding'] as bool? ?? false,
paychannels: json['paychannels'] as String?,
);
Map<String, dynamic> _$AppInfoToJson(AppInfo instance) => <String, dynamic>{
@ -46,4 +48,6 @@ Map<String, dynamic> _$AppInfoToJson(AppInfo instance) => <String, dynamic>{
'description': instance.description,
'version': instance.version,
'tourists': instance.tourists,
'allowskipsevicebinding': instance.allowskipdevicebinding,
'paychannels': instance.paychannels,
};

239
lib/data/models/goods.dart

@ -0,0 +1,239 @@
/// 商品类型
/// 0: 普通产品 normal
/// 1: 会员产品 member
import 'dart:convert';
// 使用量类型(与后端/Proto枚举对应)
enum UsageType {
/// 未知使用量类型
UsageNull, // 0
/// 翻译
Translation, // 1
/// 会议
Meet, // 2
/// 智能体
AI, // 3
/// 智能体
Vip; // 4
/// Vip
// 解析支持 int 或 string(大小写不敏感)
static UsageType from(dynamic value) {
if (value is int) {
switch (value) {
case 0:
return UsageType.UsageNull;
case 1:
return UsageType.Translation;
case 2:
return UsageType.Meet;
case 3:
return UsageType.AI;
case 4:
return UsageType.Vip;
default:
return UsageType.UsageNull;
}
}
if (value is String) {
final v = int.tryParse(value.trim());
if (v != null) return UsageType.from(v);
switch (value.trim().toLowerCase()) {
case 'usagenull':
case 'null':
case 'unknown':
return UsageType.UsageNull;
case 'translation':
return UsageType.Translation;
case 'meet':
case 'meeting':
return UsageType.Meet;
case 'ai':
return UsageType.AI;
case 'vip':
return UsageType.Vip;
default:
return UsageType.UsageNull;
}
}
return UsageType.UsageNull;
}
int get toInt {
switch (this) {
case UsageType.UsageNull:
return 0;
case UsageType.Translation:
return 1;
case UsageType.Meet:
return 2;
case UsageType.AI:
return 3;
case UsageType.Vip:
return 4;
}
}
String get name {
switch (this) {
case UsageType.UsageNull:
return 'UsageNull';
case UsageType.Translation:
return 'Translation';
case UsageType.Meet:
return 'Meet';
case UsageType.AI:
return 'AI';
case UsageType.Vip:
return 'Vip';
}
}
}
/// 支付商品模型,与后端 DBGoods 对应
/// - id: 产品id
/// - enable: 是否启用
/// - name: 产品名称
/// - desc: 产品描述
/// - price: 产品价格(建议单位:分)
/// - usagetype: 产品类型 0:普通产品 1:会员产品
/// - usagenum: 使用量(时长/次数/额度等)
class DBGoods {
final String id;
final bool enable;
final String name;
final String localname;
final int price; // 建议单位:分
final UsageType usagetype;
final int usagenum;
const DBGoods({
required this.id,
required this.enable,
required this.name,
required this.localname,
required this.price,
required this.usagetype,
required this.usagenum,
});
/// 解析后端 JSON
factory DBGoods.fromJson(Map<String, dynamic> json) {
String _asString(dynamic v) {
if (v == null) return '';
return v is String ? v : v.toString();
}
bool _asBool(dynamic v) {
if (v is bool) return v;
if (v is num) return v != 0;
if (v is String) {
final s = v.trim().toLowerCase();
return s == 'true' || s == '1';
}
return false;
}
int _asInt(dynamic v) {
if (v == null) return 0;
if (v is int) return v;
if (v is num) return v.toInt();
if (v is String) return int.tryParse(v) ?? 0;
return 0;
}
return DBGoods(
id: _asString(json['id']),
enable: _asBool(json['enable']),
name: _asString(json['name']),
localname: _asString(json['localname']),
price: _asInt(json['price']),
usagetype: UsageType.from(json['usagetype']),
usagenum: _asInt(json['usagenum']),
);
}
/// 编码为后端 JSON
Map<String, dynamic> toJson() {
return {
'id': id,
'enable': enable,
'name': name,
'localname': localname,
'price': price,
'usagetype': usagetype.toInt,
'usagenum': usagenum,
};
}
/// 列表解析
static List<DBGoods> listFromJson(dynamic data) {
if (data == null) return const [];
if (data is List) {
return data
.map((e) => DBGoods.fromJson(e as Map<String, dynamic>))
.toList();
}
// 某些接口返回 { list: [...] } 或 { data: [...] }
if (data is Map<String, dynamic>) {
final list = data['list'] ?? data['data'] ?? data['items'];
if (list is List) {
return list
.map((e) => DBGoods.fromJson(e as Map<String, dynamic>))
.toList();
}
}
return const [];
}
/// 价格换算:分 -> 元(仅当 price 单位为分时使用)
double get priceYuan => price / 100.0;
/// 用于支付创建订单的金额(分)
int get payAmountCents => price;
DBGoods copyWith({
String? id,
bool? enable,
String? name,
String? localname,
int? price,
UsageType? usagetype,
int? usagenum,
}) {
return DBGoods(
id: id ?? this.id,
enable: enable ?? this.enable,
name: name ?? this.name,
localname: localname ?? this.localname,
price: price ?? this.price,
usagetype: usagetype ?? this.usagetype,
usagenum: usagenum ?? this.usagenum,
);
}
@override
String toString() {
return 'DBGoods(id: $id, enable: $enable, name: $name, price: $price, usagetype: ${usagetype.name}, usagenum: $usagenum)';
}
Map<String, dynamic>? get _localnameMap {
if (localname.isEmpty) return null;
try {
final v = jsonDecode(localname);
if (v is Map<String, dynamic>) return v;
} catch (_) {}
return null;
}
Map<String, dynamic> localInfo(String tag) {
final m = _localnameMap;
if (m == null) return const {};
final key1 = tag;
final key2 = tag.replaceAll('_', '-');
final key3 = tag.replaceAll('-', '_');
dynamic e = m[key1] ?? m[key2] ?? m[key3];
if (e == null && m.isNotEmpty) e = m.values.first;
return e is Map<String, dynamic> ? e as Map<String, dynamic> : const {};
}
}

292
lib/data/models/meeting_usage_stats.dart

@ -0,0 +1,292 @@
///会议模块用量统计的模型类
// ============== ASR 状态常量 ==============
const int asrStatusProcessing = 0; // 处理中
const int asrStatusFailed = 1; // 处理失败
const int asrStatusCompleted = 2; // 已完成
// ============== ASR 单次记录 ==============
// 会议音频文件转文字单次数据
class MeetingAsrRecord {
String id; // 本次ASR唯一标识
int meetingId; // 会议记录ID
String taskId; // 云端任务ID
int audioSeconds; // 音频总时长(秒)
int fileSizeBytes; // 音频文件大小(字节)
String language; // ASR语言
int submitTimestamp; // 提交时间戳(毫秒)
int status; // 状态: 0-处理中, 1-处理失败, 2-已完成
int transcriptBytes; // 转写后的字节数(utf8)
int completeTimestamp; // 完成时间戳(毫秒)
MeetingAsrRecord({
required this.id,
required this.meetingId,
required this.taskId,
required this.audioSeconds,
required this.fileSizeBytes,
required this.language,
required this.submitTimestamp,
required this.status,
required this.transcriptBytes,
required this.completeTimestamp,
});
Map<String, dynamic> toJson() => {
'id': id,
'meetingId': meetingId,
'taskId': taskId,
'audioSeconds': audioSeconds,
'fileSizeBytes': fileSizeBytes,
'language': language,
'submitTimestamp': submitTimestamp,
'status': status,
'transcriptBytes': transcriptBytes,
'completeTimestamp': completeTimestamp,
};
factory MeetingAsrRecord.fromJson(Map<String, dynamic> json) {
return MeetingAsrRecord(
id: json['id'] ?? '',
meetingId: json['meetingId'] ?? 0,
taskId: json['taskId'] ?? '',
audioSeconds: json['audioSeconds'] ?? 0,
fileSizeBytes: json['fileSizeBytes'] ?? 0,
language: json['language'] ?? '',
submitTimestamp: json['submitTimestamp'] ?? 0,
status: json['status'] ?? 0,
transcriptBytes: json['transcriptBytes'] ?? 0,
completeTimestamp: json['completeTimestamp'] ?? 0,
);
}
}
// ============== 对象存储单次记录 ==============
// 对象存储单次上传记录
class MeetingObjectStorageRecord {
int meetingId; // 会议记录ID
String storageUrl; // 云端存储URL
int storageBytes; // 文件大小(字节)
int transferBytes; // 实际传输字节数
int uploadTimestamp; // 上传完成时间戳(毫秒)
MeetingObjectStorageRecord({
required this.meetingId,
required this.storageUrl,
required this.storageBytes,
required this.transferBytes,
required this.uploadTimestamp,
});
Map<String, dynamic> toJson() => {
'meetingId': meetingId,
'storageUrl': storageUrl,
'storageBytes': storageBytes,
'transferBytes': transferBytes,
'uploadTimestamp': uploadTimestamp,
};
factory MeetingObjectStorageRecord.fromJson(Map<String, dynamic> json) {
int _asInt(dynamic v) {
if (v == null) return 0;
if (v is int) return v;
if (v is num) return v.toInt();
if (v is String) return int.tryParse(v) ?? 0;
return 0;
}
return MeetingObjectStorageRecord(
meetingId: _asInt(json['meetingId']),
storageUrl: (json['storageUrl'] ?? '').toString(),
storageBytes: _asInt(json['storageBytes']),
transferBytes: _asInt(json['transferBytes']),
uploadTimestamp: _asInt(json['uploadTimestamp']),
);
}
}
// 会议音频文件转文字单日统计
class MeetingAsrDailyStats {
String date; // 日期字符串: YYYY-MM-DD
String userId; // 用户ID
List<MeetingAsrRecord> items; // 当天所有单次ASR
MeetingAsrDailyStats({
required this.date,
required this.userId,
required this.items,
});
// 计算型聚合,不冗余存储
int get asrCalls => items.length;
int get audioSecondsTotal => items.fold(0, (s, r) => s + r.audioSeconds);
int get audioBytesTotal => items.fold(0, (s, r) => s + r.fileSizeBytes);
int get transcriptBytesTotal =>
items.fold(0, (s, r) => s + r.transcriptBytes);
Map<String, dynamic> toJson() => {
'date': date,
'userId': userId,
'items': items.map((e) => e.toJson()).toList(),
};
factory MeetingAsrDailyStats.fromJson(Map<String, dynamic> json) {
final list = (json['items'] as List? ?? [])
.map((e) => MeetingAsrRecord.fromJson(Map<String, dynamic>.from(e)))
.toList();
return MeetingAsrDailyStats(
date: json['date'] ?? '',
userId: json['userId'] ?? 'anonymous',
items: list,
);
}
}
// ============== 对象存储单日统计 ==============
// 👇 职责单一:仅统计对象存储相关数据
class MeetingStorageDailyStats {
String date; // 日期字符串: YYYY-MM-DD
String userId; // 用户ID
List<MeetingObjectStorageRecord> items; // 当天所有单次对象存储记录
MeetingStorageDailyStats({
required this.date,
required this.userId,
required this.items,
});
// 对象存储 聚合计算
int get storageUploads => items.length;
int get storageBytesTotal => items.fold(0, (s, r) => s + r.storageBytes);
int get transferBytesTotal => items.fold(0, (s, r) => s + r.transferBytes);
Map<String, dynamic> toJson() => {
'date': date,
'userId': userId,
'items': items.map((e) => e.toJson()).toList(),
};
factory MeetingStorageDailyStats.fromJson(Map<String, dynamic> json) {
final storageList = (json['items'] as List? ?? [])
.map((e) =>
MeetingObjectStorageRecord.fromJson(Map<String, dynamic>.from(e)))
.toList();
return MeetingStorageDailyStats(
date: json['date'] ?? '',
userId: json['userId'] ?? 'anonymous',
items: storageList,
);
}
}
// 会议音频文件转文字历史统计(所有的用量)
class MeetingAsrHistoryStats {
String userId; // 用户ID
int allAsrCalls; // 所有ASR调用次数
int allAudioSeconds; // 所有音频总时长(秒)
int allAudioFileBytes; // 所有音频文件大小(字节)
int allTranscriptBytes; // 所有转写后的字节数(utf8)
MeetingAsrHistoryStats({
required this.userId,
required this.allAsrCalls,
required this.allAudioSeconds,
required this.allAudioFileBytes,
required this.allTranscriptBytes,
});
Map<String, dynamic> toJson() => {
'userId': userId,
'allAsrCalls': allAsrCalls,
'allAudioSeconds': allAudioSeconds,
'allAudioFileBytes': allAudioFileBytes,
'allTranscriptBytes': allTranscriptBytes,
};
factory MeetingAsrHistoryStats.fromJson(Map<String, dynamic> json) {
int _asInt(dynamic v) {
if (v == null) return 0;
if (v is int) return v;
if (v is num) return v.toInt();
if (v is String) return int.tryParse(v) ?? 0;
return 0;
}
return MeetingAsrHistoryStats(
userId: json['userId'] ?? 'anonymous',
allAsrCalls: _asInt(json['allAsrCalls']),
allAudioSeconds: _asInt(json['allAudioSeconds']),
allAudioFileBytes: _asInt(json['allAudioFileBytes']),
allTranscriptBytes: _asInt(json['allTranscriptBytes']),
);
}
}
// ============== 对象存储历史统计 ==============
// 👇 职责单一:仅统计对象存储累计数据
class MeetingStorageHistoryStats {
String userId; // 用户ID
int allStorageUploads; // 所有对象存储上传次数
int allStorageBytes; // 所有存储文件总大小(字节)
int allTransferBytes; // 所有传输总字节数
MeetingStorageHistoryStats({
required this.userId,
required this.allStorageUploads,
required this.allStorageBytes,
required this.allTransferBytes,
});
Map<String, dynamic> toJson() => {
'userId': userId,
'allStorageUploads': allStorageUploads,
'allStorageBytes': allStorageBytes,
'allTransferBytes': allTransferBytes,
};
factory MeetingStorageHistoryStats.fromJson(Map<String, dynamic> json) {
int _asInt(dynamic v) {
if (v == null) return 0;
if (v is int) return v;
if (v is num) return v.toInt();
if (v is String) return int.tryParse(v) ?? 0;
return 0;
}
return MeetingStorageHistoryStats(
userId: json['userId'] ?? 'anonymous',
allStorageUploads: _asInt(json['allStorageUploads']),
allStorageBytes: _asInt(json['allStorageBytes']),
allTransferBytes: _asInt(json['allTransferBytes']),
);
}
}
// 👇 当需要同时展示两种统计时使用
class MeetingUsageDailySnapshot {
String date;
String userId;
MeetingAsrDailyStats? asrStats;
MeetingStorageDailyStats? storageStats;
MeetingUsageDailySnapshot({
required this.date,
required this.userId,
this.asrStats,
this.storageStats,
});
}
class MeetingUsageHistorySnapshot {
String userId;
MeetingAsrHistoryStats? asrStats;
MeetingStorageHistoryStats? storageStats;
MeetingUsageHistorySnapshot({
required this.userId,
this.asrStats,
this.storageStats,
});
}

41
lib/data/models/translation_usage_stats.dart

@ -1,5 +1,3 @@
/// 翻译模式统计数据
class TranslationModeStats {
final int apiCalls; // API调用次数
@ -46,7 +44,8 @@ class TranslationModeStats {
return TranslationModeStats(
apiCalls: apiCalls ?? this.apiCalls,
sourceCharacters: sourceCharacters ?? this.sourceCharacters,
effectiveAudioDuration: effectiveAudioDuration ?? this.effectiveAudioDuration,
effectiveAudioDuration:
effectiveAudioDuration ?? this.effectiveAudioDuration,
ttsCharacters: ttsCharacters ?? this.ttsCharacters,
cost: cost ?? this.cost,
);
@ -158,7 +157,7 @@ class TranslationUsageStats {
final double estimatedCost; // 预估成本
final String currency; // 货币单位
final Map<String, double> costBreakdown; // 成本分解(ASR/TTS/Translation)
TranslationUsageStats({
required this.id,
required this.date,
@ -196,7 +195,8 @@ class TranslationUsageStats {
final languagePairStatsMap = <String, LanguagePairStats>{};
if (json['languagePairStats'] != null) {
final languagePairStatsJson = json['languagePairStats'] as Map<String, dynamic>;
final languagePairStatsJson =
json['languagePairStats'] as Map<String, dynamic>;
languagePairStatsJson.forEach((key, value) {
languagePairStatsMap[key] = LanguagePairStats.fromJson(value);
});
@ -219,9 +219,15 @@ class TranslationUsageStats {
asrApiCalls: json['asrApiCalls'] ?? 0,
ttsApiCalls: json['ttsApiCalls'] ?? 0,
aiSummaryApiCalls: json['aiSummaryApiCalls'] ?? 0,
sourceTextCharacters: json['sourceTextCharacters'] ?? json['sourceCharacterCount'] ?? 0, // 兼容旧字段
effectiveAudioDuration: json['effectiveAudioDuration'] ?? json['audioRecordingDuration'] ?? 0, // 兼容旧字段
ttsTextCharacters: json['ttsTextCharacters'] ?? json['targetCharacterCount'] ?? 0, // 兼容旧字段
sourceTextCharacters: json['sourceTextCharacters'] ??
json['sourceCharacterCount'] ??
0, // 兼容旧字段
effectiveAudioDuration: json['effectiveAudioDuration'] ??
json['audioRecordingDuration'] ??
0, // 兼容旧字段
ttsTextCharacters: json['ttsTextCharacters'] ??
json['targetCharacterCount'] ??
0, // 兼容旧字段
totalSessionDuration: json['totalSessionDuration'] ?? 0,
asrNetworkBytes: json['asrNetworkBytes'] ?? 0,
ttsNetworkBytes: json['ttsNetworkBytes'] ?? 0,
@ -328,12 +334,14 @@ class TranslationUsageStats {
ttsApiCalls: ttsApiCalls ?? this.ttsApiCalls,
aiSummaryApiCalls: aiSummaryApiCalls ?? this.aiSummaryApiCalls,
sourceTextCharacters: sourceTextCharacters ?? this.sourceTextCharacters,
effectiveAudioDuration: effectiveAudioDuration ?? this.effectiveAudioDuration,
effectiveAudioDuration:
effectiveAudioDuration ?? this.effectiveAudioDuration,
ttsTextCharacters: ttsTextCharacters ?? this.ttsTextCharacters,
totalSessionDuration: totalSessionDuration ?? this.totalSessionDuration,
asrNetworkBytes: asrNetworkBytes ?? this.asrNetworkBytes,
ttsNetworkBytes: ttsNetworkBytes ?? this.ttsNetworkBytes,
translationNetworkBytes: translationNetworkBytes ?? this.translationNetworkBytes,
translationNetworkBytes:
translationNetworkBytes ?? this.translationNetworkBytes,
sessionCount: sessionCount ?? this.sessionCount,
modeStats: modeStats ?? this.modeStats,
languagePairStats: languagePairStats ?? this.languagePairStats,
@ -345,7 +353,8 @@ class TranslationUsageStats {
}
/// 获取总API调用次数
int get totalApiCalls => translationApiCalls + asrApiCalls + ttsApiCalls + aiSummaryApiCalls;
int get totalApiCalls =>
translationApiCalls + asrApiCalls + ttsApiCalls + aiSummaryApiCalls;
/// 获取总字符数(精确计费基础)
int get totalCharacterCount => sourceTextCharacters + ttsTextCharacters;
@ -354,19 +363,21 @@ class TranslationUsageStats {
int get totalAudioDuration => effectiveAudioDuration + totalSessionDuration;
/// 获取总网络流量
int get totalNetworkBytes => asrNetworkBytes + ttsNetworkBytes + translationNetworkBytes;
int get totalNetworkBytes =>
asrNetworkBytes + ttsNetworkBytes + translationNetworkBytes;
/// 获取最常用的语言对
String get mostUsedLanguagePair {
if (languagePairStats.isEmpty) return '无数据';
if (languagePairStats.isEmpty) return 'null';
return languagePairStats.entries
.reduce((a, b) => a.value.translationCount > b.value.translationCount ? a : b)
.reduce((a, b) =>
a.value.translationCount > b.value.translationCount ? a : b)
.key;
}
/// 获取最常用的翻译模式
String get mostUsedMode {
if (modeStats.isEmpty) return '无数据';
if (modeStats.isEmpty) return 'null';
return modeStats.entries
.reduce((a, b) => a.value.apiCalls > b.value.apiCalls ? a : b)
.key;

95
lib/data/models/user_Info.dart

@ -1,10 +1,14 @@
import 'package:get_storage/get_storage.dart';
import 'package:get/get.dart';
import '../../../core/utils/logger.dart';
class User {
// 单例实例
static User? _instance;
/// 全局刷新信号(当用户信息更新时 +1,用于驱动UI重建)
static final RxInt refreshTick = 0.obs;
/// 安全地检查用户是否已经登录(即单例是否已初始化)
static bool isLoggedIn() {
return _instance != null;
@ -41,6 +45,13 @@ class User {
String phonemac;
String password;
int viplv = 0; //添加会员等级字段,0表示普通用户
int vipexptime = 0; // 会员到期/剩余时间(秒/毫秒,按后端定义)
int aichatintegral = 0; // ai聊天积分
int aichattotalintegral = 0; // ai聊天总积分
int tradeintegral = 0; // 翻译积分
int tradetotalintegral = 0; // 翻译总积分
int meetintegral = 0; // 会议积分
int meettotalintegral = 0; // 会议总积分
List<UserDevice> devices;
@ -56,6 +67,13 @@ class User {
required this.phonemac,
required this.password,
required this.viplv,
required this.vipexptime,
required this.aichatintegral,
required this.aichattotalintegral,
required this.tradeintegral,
required this.tradetotalintegral,
required this.meetintegral,
required this.meettotalintegral,
required this.devices,
});
@ -65,51 +83,95 @@ class User {
final devicesData = json['devices'] as List<dynamic>?; // 允许空值
//final token = json['data']['token'] as String? ?? '';
//final token = '';
// 更新单例实例
return _instance = User._(
final u = User._(
token: '',
//token: token as String? ?? '',
name: (userData?['name'] as String?) ?? '默认名称', // 提供默认值
name: (userData?['name'] as String?) ?? '默认名称',
uid: (userData?['uid'] as String?) ?? '',
avatar: (userData?['avatar'] as String?) ?? '',
language: (userData?['language'] as String?) ?? 'en',
mail: (userData?['mail'] as String?) ?? '',
phone: (userData?['phone'] as String?) ?? '',
phonemac: (userData?['phonemac'] as String?) ?? '',
password: (userData?['password'] as String?) ?? '',
viplv: (userData?['viplv'] as int?) ?? 0, // 提供默认值
vipexptime: (userData?['vipexptime'] as int?) ?? 0, // 提供默认值
aichatintegral: (userData?['aichatintegral'] as int?) ?? 0,
aichattotalintegral: (userData?['aichattotalintegral'] as int?) ?? 0,
tradeintegral: (userData?['tradeintegral'] as int?) ?? 0,
tradetotalintegral: (userData?['tradetotalintegral'] as int?) ?? 0,
meetintegral: (userData?['meetintegral'] as int?) ?? 0,
meettotalintegral: (userData?['meettotalintegral'] as int?) ?? 0,
devices: devicesData
?.map((e) => UserDevice.fromJson(e as Map<String, dynamic>))
.toList() ??
[], // 处理设备列表
[],
);
_instance = u;
Logger.i("User",
"初始化用户: uid=${u.uid}, name=${u.name}, viplv=${u.viplv}, vipexptime=${u.vipexptime}, ai聊天=${u.aichatintegral}/${u.aichattotalintegral}, 翻译=${u.tradeintegral}/${u.tradetotalintegral}, 会议=${u.meetintegral}/${u.meettotalintegral}");
return u;
}
factory User.fronTokenJson(Map<String, dynamic> json) {
// 修复1:安全获取嵌套的 user 字段
final userData = json['user'] as Map<String, dynamic>?; // 允许空值
final devicesData = json['devices'] as List<dynamic>?; // 允许空值
print("数据获取fronTokenJson$userData $devicesData");
// 更新单例实例
return _instance = User._(
Logger.d("User",
"fronTokenJson: user=$userData, devices=${devicesData?.length ?? 0}");
final u = User._(
token: '',
name: (userData?['name'] as String?) ?? '默认名称', // 提供默认值
name: (userData?['name'] as String?) ?? '默认名称',
uid: (userData?['uid'] as String?) ?? '',
avatar: (userData?['avatar'] as String?) ?? '',
language: (userData?['language'] as String?) ?? 'en',
mail: (userData?['mail'] as String?) ?? '',
phone: (userData?['phone'] as String?) ?? '',
phonemac: (userData?['phonemac'] as String?) ?? '',
password: (userData?['password'] as String?) ?? '',
viplv: (userData?['viplv'] as int?) ?? 0, // 提供默认值
vipexptime: (userData?['vipexptime'] as int?) ?? 0, // 提供默认值
aichatintegral: (userData?['aichatintegral'] as int?) ?? 0,
aichattotalintegral: (userData?['aichattotalintegral'] as int?) ?? 0,
tradeintegral: (userData?['tradeintegral'] as int?) ?? 0,
tradetotalintegral: (userData?['tradetotalintegral'] as int?) ?? 0,
meetintegral: (userData?['meetintegral'] as int?) ?? 0,
meettotalintegral: (userData?['meettotalintegral'] as int?) ?? 0,
devices: devicesData != null
? (devicesData)
.map((e) => UserDevice.fromJson(e as Map<String, dynamic>))
.toList()
: [], // 处理设备列表
: [],
);
_instance = u;
Logger.i("User",
"初始化用户(token): uid=${u.uid}, name=${u.name}, viplv=${u.viplv}, vipexptime=${u.vipexptime}, ai聊天=${u.aichatintegral}/${u.aichattotalintegral}, 翻译=${u.tradeintegral}/${u.tradetotalintegral}, 会议=${u.meetintegral}/${u.meettotalintegral}");
return u;
}
updateUserInfo(Map<String, dynamic> user) {
name = user['name'] as String? ?? name;
uid = user['uid'] as String? ?? uid;
avatar = user['avatar'] as String? ?? avatar;
language = user['language'] as String? ?? language;
token = user['token'] as String? ?? token;
mail = user['mail'] as String? ?? mail;
phone = user['phone'] as String? ?? phone;
phonemac = user['phonemac'] as String? ?? phonemac;
password = user['password'] as String? ?? password;
viplv = user['viplv'] as int? ?? viplv;
vipexptime = user['vipexptime'] as int? ?? vipexptime;
aichatintegral = user['aichatintegral'] as int? ?? aichatintegral;
aichattotalintegral =
user['aichattotalintegral'] as int? ?? aichattotalintegral;
tradeintegral = user['tradeintegral'] as int? ?? tradeintegral;
tradetotalintegral =
user['tradetotalintegral'] as int? ?? tradetotalintegral;
meetintegral = user['meetintegral'] as int? ?? meetintegral;
meettotalintegral = user['meettotalintegral'] as int? ?? meettotalintegral;
// 触发全局刷新信号,驱动依赖UI重建
refreshTick.value++;
}
// 完整的JSON序列化
@ -125,6 +187,13 @@ class User {
'phonemac': phonemac,
'password': password,
'viplv': viplv,
'vipexptime': vipexptime,
'aichatintegral': aichatintegral,
'aichattotalintegral': aichattotalintegral,
'tradeintegral': tradeintegral,
'tradetotalintegral': tradetotalintegral,
'meetintegral': meetintegral,
'meettotalintegral': meettotalintegral,
'devices': devices.map((device) => device.toJson()).toList(),
},
};

8
lib/data/services/account_service.dart

@ -6,6 +6,8 @@ import '../../modules/login/controllers/googleLogin.dart';
import '../../modules/login/controllers/facebookLogin.dart';
import '../services/network/api.dart';
import 'db/database_helper.dart';
import 'meeting/meeting_task_service.dart';
import '../../data/models/user_Info.dart';
/// 账号管理服务
///
@ -32,6 +34,7 @@ class AccountService extends GetxService {
await _storage.write("logintoken", null);
await _storage.write("user_info", null);
await _storage.write("local_avatar", null);
User.clearUserSession();
logger.d('用户数据清理成功');
return true;
} catch (e) {
@ -44,6 +47,7 @@ class AccountService extends GetxService {
// 清理所有用户数据
try {
await _storage.erase();
User.clearUserSession();
logger.d('所有用户数据清理成功');
return true;
} catch (e) {
@ -79,6 +83,10 @@ class AccountService extends GetxService {
/// 返回操作结果,包含成功状态和错误信息
Future<AccountOperationResult> signOut() async {
try {
// 清除会议记录任务列表
final taskService = Get.find<MeetingTaskService>();
taskService.cancelTask();
// 上传会议记录操作记录
await Synchrodata.uploadOperationRecords();

5
lib/data/services/asr_service.dart

@ -20,8 +20,9 @@ abstract class AsrService {
///
/// 返回一个包含识别事件的流
Future<bool> startContinuousRecognition(
bool audioSourceType,
);
bool audioSourceType, {
bool isRemoveFirstPunctuation = true,
});
/// 停止连续语音识别
Future<bool> stopContinuousRecognition();

133
lib/data/services/ble_manager.dart

@ -2,17 +2,20 @@ import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:get_storage/get_storage.dart';
import 'package:get/get.dart';
import 'package:ble_service/ble_service.dart';
import 'package:agent_service/agent_service.dart';
import '../models/user_Info.dart' as userInfo;
import '/data/models/appconfig_model.dart';
import '../../data/models/appconfig.dart';
import '../../core/utils/logger.dart';
import 'bluetooth_manager.dart';
import 'language_manager.dart';
import 'network/dio_manager.dart';
// 重新导出BLE连接状态常量,让外部可以通过BleManager访问
export 'package:ble_service/ble_service.dart' show BleConnectionState;
@ -27,6 +30,67 @@ class BleCommands {
static const int GET_WAKEUP_VERSION = 0x08;
}
/// 判断编解码控制指令是否成功
///
/// 根据 rawData 第二字节是否为非 0 来判断:
/// - 成功:第二字节不为 0
/// - 失败或无法解析:返回 false
bool _isCodecControlSuccess(Map<dynamic, dynamic> data) {
final dynamic raw = data['rawData'];
if (raw == null) return false;
int? secondByte;
if (raw is List) {
if (raw.length >= 2) {
final s = raw[1];
if (s is int) {
secondByte = s;
} else if (s is num) {
secondByte = s.toInt();
} else if (s is String) {
final t = s.trim();
if (t.startsWith('0x') || t.startsWith('0X')) {
secondByte = int.tryParse(t.substring(2), radix: 16);
} else {
secondByte = int.tryParse(t);
}
}
}
} else if (raw is String) {
final normalized = raw.trim().replaceAll('[', '').replaceAll(']', '');
final parts =
normalized.split(RegExp(r'[,\s]+')).where((e) => e.isNotEmpty).toList();
if (parts.length >= 2) {
final t = parts[1].trim();
if (t.startsWith('0x') || t.startsWith('0X')) {
secondByte = int.tryParse(t.substring(2), radix: 16);
} else {
secondByte = int.tryParse(t);
}
}
} else if (raw is Map) {
final dynamic s = raw['second'] ?? raw['status2'] ?? raw['result'];
if (s is int) {
secondByte = s;
} else if (s is num) {
secondByte = s.toInt();
} else if (s is String) {
final t = s.trim();
if (t.startsWith('0x') || t.startsWith('0X')) {
secondByte = int.tryParse(t.substring(2), radix: 16);
} else {
secondByte = int.tryParse(t);
}
}
} else {
// 无法解析的类型
return false;
}
return secondByte != null && secondByte != 0;
}
/// 蓝牙设备信息缓存模型
class DeviceInfo {
final String address;
@ -147,12 +211,12 @@ class BleManager extends GetxService {
// 设备信息缓存
final deviceInfo = Rx<DeviceInfo?>(null); // 使用 Rx 包装
final _wakeupVoiceUpgradeProgress = 0.obs; // 唤醒语音升级进度
RxInt get wakeupVoiceUpgradeProgress => _wakeupVoiceUpgradeProgress;
final _wakeupVoiceUpgradeStatus =
0.obs; // 唤醒语音升级状态 0: 未升级 1: 升级中 2: 升级成功 3: 升级失败
RxInt get wakeupVoiceUpgradeStatus => _wakeupVoiceUpgradeStatus;
//添加编码器状态跟踪
final _isCodecActive = false.obs;
bool get isCodecActive => _isCodecActive.value;
RxBool get isCodecActiveRx => _isCodecActive;
bool _awaitingCodecOpen = false; //是否正在等待编码器打开的成功应答
bool _awaitingCodecClose = false; //是否正在等待编码器关闭的成功应答
// 订阅
StreamSubscription<dynamic>? _statusSubscription;
@ -218,7 +282,9 @@ class BleManager extends GetxService {
state == BleConnectionState.error) {
Logger.info('lxm--BLE设备已断开或发生错误');
_isConnected.value = false;
// 更新设备信息Add commentMore actions
_awaitingCodecOpen = false;
_awaitingCodecClose = false;
_isCodecActive.value = false;
Logger.info('lxm--断开连接时重置设备信息为0');
_updateDeviceInfoIfNeeded(
batteryLevel: 0,
@ -350,7 +416,27 @@ class BleManager extends GetxService {
Logger.info('lxm--处理编解码控制命令');
// 处理通话状态
print(" CONTROL_CODEC: $commandId,$data");
//_isCall.value = data['callStatus'] as bool? ?? false;
final bool codecSuccess = _isCodecControlSuccess(data);
if (_awaitingCodecOpen) {
//如果正在等待打开编解码器
_isCodecActive.value = codecSuccess; // 只在等待打开时更新状态
_awaitingCodecOpen = false;
} else if (_awaitingCodecClose) {
if (codecSuccess) {
_isCodecActive.value = false;
}
_awaitingCodecClose = false;
}
if (codecSuccess) {
print("lxm--编解码控制成功 (rawData 第二字节非 0)");
Logger.info('lxm--编解码控制成功 (rawData 第二字节非 0)');
} else {
print("lxm--编解码控制失败 (rawData 为 [162, 0] 或无法解析)");
Logger.warning('lxm--编解码控制失败 (rawData 为 [162, 0] 或无法解析)');
}
break;
case BleCommands.GET_WAKEUP_VERSION:
Logger.info('lxm--处理唤醒语音版本命令');
@ -760,10 +846,7 @@ class BleManager extends GetxService {
Future<bool> startAgentService() async {
try {
// 从.env文件直接读取环境变量
var serverurl = dotenv.env['SERVER_URL'] ?? '';
if (Get.locale?.countryCode != 'CN') {
serverurl = dotenv.env['HW_SERVER_URL'] ?? '';
}
var serverurl = DioManager().baseUrl;
var jsonString = _storage.read<String>("logintoken");
@ -791,6 +874,9 @@ class BleManager extends GetxService {
Logger.info('启动BLE服务,musicServiceType: ${musicServiceType}');
final isTtsInterruptEnabled = await _loadTtsInterrupe();
final vipExpiryTime = userInfo.User.instance.vipexptime;
Logger.info('liwei------ vipexptime 1: $vipExpiryTime');
// 根据APP语言动态配置语音识别语言
List<String> supportedLanguages = [];
try {
@ -861,7 +947,9 @@ class BleManager extends GetxService {
'musicServiceType': musicServiceType,
"navigationMode": navigationMode,
"isttsinterrupt": isTtsInterruptEnabled ? "true" : "false",
"callingTool": "callingTool".tr
"vipexptime": vipExpiryTime, //会员过期时间
"callingToolText": "callingTool".tr,
"insufficientIntegralText": "insufficientIntegral".tr,
};
// 记录日志(不记录敏感信息)
@ -995,19 +1083,27 @@ class BleManager extends GetxService {
/// 打开解码器
Future<bool> openDecoder() async {
try {
_awaitingCodecOpen = true;
_awaitingCodecClose = false;
_isCodecActive.value = false;
return await _bleService.openDecoder();
} catch (e) {
Logger.error('打开解码器失败: ${e.toString()}');
_awaitingCodecOpen = false;
return false;
}
}
/// 打开解码器
/// 打开A2DP解码器
Future<bool> openA2DPDecoder() async {
try {
_awaitingCodecOpen = true;
_awaitingCodecClose = false;
_isCodecActive.value = false;
return await _bleService.openA2DPDecoder();
} catch (e) {
Logger.error('打开解码器失败: ${e.toString()}');
_awaitingCodecOpen = false;
return false;
}
}
@ -1025,9 +1121,13 @@ class BleManager extends GetxService {
/// 关闭编解码器
Future<bool> closeCodec() async {
try {
_awaitingCodecOpen = false;
_awaitingCodecClose = true;
_isCodecActive.value = false;
return await _bleService.closeCodec();
} catch (e) {
Logger.error('关闭编解码器失败: ${e.toString()}');
_awaitingCodecClose = false;
return false;
}
}
@ -1171,6 +1271,11 @@ class BleManager extends GetxService {
List<String>? uuids,
}) async {
try {
// 在注册新设备前先清除旧设备信息
if (macAddress != null && macAddress != currentDeviceAddress) {
clearDeviceInfo(); // 清除上一个设备的信息
}
// 保存设备地址信息
if (macAddress != null) {
currentDeviceAddress = macAddress;

15
lib/data/services/bluetooth_manager.dart

@ -1,6 +1,7 @@
import 'dart:async';
import 'package:get/get.dart';
import 'package:classic_bluetooth/classic_bluetooth.dart';
import 'package:get_storage/get_storage.dart';
import '../../core/utils/logger.dart';
import '../../routes/app_routes.dart';
import 'ble_manager.dart';
@ -21,6 +22,7 @@ class BluetoothManager extends GetxService {
final Rx<BluetoothDevice?> currentDeviceRx = Rx<BluetoothDevice?>(null);
BluetoothDevice? get currentDevice => currentDeviceRx.value;
final BleManager _bleManager = Get.find<BleManager>();
final GetStorage _storage = GetStorage();
// 订阅
StreamSubscription<BluetoothEvent>? _bluetoothSubscription;
@ -76,7 +78,8 @@ class BluetoothManager extends GetxService {
currentDeviceRx.value = newDevice;
// 检查当前是否在OTA升级界面,如果是则不跳转
if (!_isInOtaUpgradePage() &&
if (_isLoggedIn() &&
!_isInOtaUpgradePage() &&
!_bleManager.isConnected &&
Get.currentRoute != Routes.pairing) {
Get.toNamed(Routes.pairing, arguments: newDevice);
@ -161,4 +164,14 @@ class BluetoothManager extends GetxService {
return false;
}
}
/// 是否已登录
bool _isLoggedIn() {
try {
final token = _storage.read('logintoken');
return token != null && token is String && token.isNotEmpty;
} catch (e) {
return false;
}
}
}

4
lib/data/services/deapsound_ai_service.dart

@ -78,6 +78,10 @@ class DeapsoundAIService implements AiService {
..body = jsonEncode(requestBody);
final response = await client.send(request);
if (response.statusCode != 200) {
throw Exception('Unknown error');
}
await for (final chunk in response.stream
.transform(utf8.decoder)
.transform(const LineSplitter())) {

105
lib/data/services/meeting/meeting_task_aggregator.dart

@ -0,0 +1,105 @@
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'meeting_task_service.dart';
import 'meeting_task_service2.dart';
/// 会议助手任务服务聚合器(统一列表与状态)
class MeetingTaskAggregator extends GetxService {
final GetStorage _storage = GetStorage();
final MeetingTaskService s1 = Get.find<MeetingTaskService>();
final MeetingTaskService2 s2 = Get.find<MeetingTaskService2>();
RxList taskFinishList = [].obs;
RxInt tasktype = 1.obs;
int meetingId = 0;
List textList = [];
Worker? _w1;
Worker? _w2;
Worker? _wTasktype;
@override
void onInit() {
super.onInit();
_w1 = ever(s1.taskFinishList, (_) => _rebuild());
_w2 = ever(s2.taskFinishList, (_) => _rebuild());
_rebuild();
}
void setMeeting(int id) {
meetingId = id;
final String svc =
(_storage.read("meeting_service_type_$id") ?? '').toString();
final bool isFast = svc == 'fast';
_wTasktype?.dispose();
if (isFast) {
_wTasktype = ever(s2.tasktype, (value) {
tasktype.value = value;
if (value == 2) {
textList = s2.textList;
}
});
} else {
_wTasktype = ever(s1.tasktype, (value) {
tasktype.value = value;
if (value == 2) {
textList = s1.textList;
}
});
}
}
void clearMeeting() {
meetingId = 0;
_wTasktype?.dispose();
_wTasktype = null;
}
void _rebuild() {
final Set<int> ids = {};
for (var e in s1.taskFinishList) {
if (e is Map && e['id'] is int) ids.add(e['id'] as int);
}
for (var e in s2.taskFinishList) {
if (e is Map && e['id'] is int) ids.add(e['id'] as int);
}
final List unified = [];
for (final id in ids) {
final String svc =
(_storage.read("meeting_service_type_$id") ?? '').toString();
final Map a = s1.taskFinishList.firstWhere(
(x) => x['id'] == id,
orElse: () => {},
);
final Map b = s2.taskFinishList.firstWhere(
(x) => x['id'] == id,
orElse: () => {},
);
int va = a.isNotEmpty ? ((a['tasktype'] ?? 0) as int) : -999;
int vb = b.isNotEmpty ? ((b['tasktype'] ?? 0) as int) : -999;
int v;
if (svc == 'fast') {
if (va != -999 && vb != -999) {
v = va >= vb ? va : vb;
} else {
v = vb != -999 ? vb : va;
}
} else if (svc == 'standard') {
if (va != -999 && vb != -999) {
v = va >= vb ? va : vb;
} else {
v = va != -999 ? va : vb;
}
} else {
if (va == -999 && vb == -999) {
continue;
}
v = va == -999 ? vb : (vb == -999 ? va : (va >= vb ? va : vb));
}
unified.add({'id': id, 'tasktype': v});
}
taskFinishList.value = unified;
}
}

141
lib/data/services/meeting/meeting_task_service.dart

@ -1,4 +1,5 @@
import 'dart:convert';
import 'dart:io';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
@ -6,16 +7,20 @@ import 'package:http/http.dart' as http;
import '../../../core/utils/logger.dart';
import '../../../core/utils/synchrodata.dart';
import '../../models/meeting_usage_stats.dart';
import '../db/sqflite_api.dart';
import '../deapsound_ai_service.dart';
import '../usage_stats_service.dart';
import 'meeting_upload_service.dart';
import '../../../data/models/appconfig.dart';
import 'summary_task_service.dart';
///会议任务服务类,负责管理会议音频的转写任务处理流程,包括任务提交、状态轮询、结果处理和AI分析等功能。
///火山引擎录音文件识别大模型-标准版
class MeetingTaskService extends GetxService {
final GetStorage _storage = GetStorage();
MeetingUploadService get _uploadService => Get.find<MeetingUploadService>();
SummaryTaskService get _summaryTaskService => Get.find<SummaryTaskService>();
List _taskList = []; //待处理的会议任务列表
RxList taskFinishList = [].obs; //已处理的会议任务列表
@ -45,8 +50,6 @@ class MeetingTaskService extends GetxService {
int meetingId = 0;
RxInt tasktype = 1.obs; //任务类型,1-转写中,2-总结中,3-完成
List textList = []; //转写结果列表
String summary = ''; //AI总结内容
String overview = ''; //AI概览内容
@override
void onInit() {
@ -58,6 +61,15 @@ class MeetingTaskService extends GetxService {
_getTaskList();
}
void cancelTask() {
_isTask = false;
_taskList.clear();
_storage.remove("meeting_task_list");
_storage.remove("meeting_task_finish_list");
_uploadService.cancelUpload();
_summaryTaskService.cancelTask();
}
Future<bool> _initialize() async {
try {
_appid = AppConfig.env('VOLC_OPENSPEECH_APP_ID') ?? '';
@ -153,6 +165,37 @@ class MeetingTaskService extends GetxService {
taskId = await _submitTask(audiourl, isSpeaker, language);
}
await SqfliteApi.editMeeting(id, {'tasktype': 1, 'taskid': taskId});
try {
final detail = await SqfliteApi.getMeetingDetails(id);
final seconds = (detail['seconds'] ?? 0) as int;
final filepath = (detail['filepath'] ?? '') as String;
int fileSizeBytes = 0;
if (filepath.isNotEmpty) {
try {
fileSizeBytes = await File(filepath).length();
} catch (_) {}
}
final record = MeetingAsrRecord(
id: taskId,
meetingId: id,
taskId: taskId,
audioSeconds: seconds,
fileSizeBytes: fileSizeBytes,
language: language,
submitTimestamp: DateTime.now().millisecondsSinceEpoch,
status: asrStatusProcessing,
transcriptBytes: 0,
completeTimestamp: 0,
);
try {
final svc = Get.isRegistered<UsageStatsService>()
? Get.find<UsageStatsService>()
: Get.put(UsageStatsService(), permanent: true);
svc.addMeetingAsrRecord(record);
} catch (e) {
Logger.w('MeetingASRrecord', '提交用量记录失败: ' + e.toString());
}
} catch (_) {}
_taskList.add({
'id': id,
'taskid': taskId,
@ -197,6 +240,7 @@ class MeetingTaskService extends GetxService {
if (isDeleteTask) {
_taskList.removeWhere((element) => element['id'] == id);
_storage.write("meeting_task_list", _taskList);
_summaryTaskService.removeTask(id);
}
}
@ -332,7 +376,8 @@ class MeetingTaskService extends GetxService {
Logger.info("lxm---大模型asr响应体结果$respDic['result']['text']");
if (respDic['result']['text'] != null) {
if (respDic['result']['text'] != null &&
respDic['result']['text'] != '') {
await _addTextList(
item['id'], //会议ID
respDic['result']['utterances'], //语音转文字结果
@ -409,77 +454,25 @@ class MeetingTaskService extends GetxService {
_storage.write("meeting_task_list", _taskList);
_storage.write("meeting_task_finish_list", taskFinishList);
}
// 触发AI分析,分别请求总结和概览
aiServiceMessage(id, text, prompt, outline);
}
///触发AI分析,分别请求总结和概览
///[id] 会议ID
///[text] 语音转文字结果
///[prompt] AI总结提示词
///[outline] AI概览提示词
void aiServiceMessage(int id, String text, String prompt, String outline) {
int awaitQuantity = 0;
String summaryText = '';
String overviewText = '';
DeapsoundAIService().sendMessage(
messages: [
{
'role': 'system',
'content': prompt,
},
{'role': 'user', 'content': text},
],
).then((value) {
awaitQuantity++;
summaryText = value;
Logger.info("lxm---大模型asr总结结果$summaryText");
if (awaitQuantity >= 2) {
_aiServiceValue(id, summaryText, overviewText);
}
});
DeapsoundAIService().sendMessage(
messages: [
{
'role': 'system',
'content': outline,
},
{'role': 'user', 'content': text},
],
).then((value) {
awaitQuantity++;
overviewText = value;
Logger.info("lxm---大模型asr概览结果$overviewText");
if (awaitQuantity >= 2) {
_aiServiceValue(id, summaryText, overviewText);
try {
final details = await SqfliteApi.getMeetingDetails(id);
final tid = (details['taskid'] ?? '') as String;
final transcriptBytes = utf8.encode(text).length;
try {
final svc = Get.isRegistered<UsageStatsService>()
? Get.find<UsageStatsService>()
: Get.put(UsageStatsService(), permanent: true);
svc.completeMeetingAsrRecord(
id: tid,
transcriptBytes: transcriptBytes,
completeTimestamp: DateTime.now().millisecondsSinceEpoch,
);
} catch (e) {
Logger.w('MeetingASRrecord', '完成用量记录失败: ' + e.toString());
}
});
}
} catch (_) {}
///处理AI分析完成后的结果,包括数据库存储和状态更新
///[id] 会议ID
///[summaryText] 总结结果
///[overviewText] 概览结果
void _aiServiceValue(int id, String summaryText, String overviewText) {
SqfliteApi.editMeeting(id, {
'tasktype': 3,
'summary': summaryText,
'overview': overviewText,
});
if (id == meetingId) {
summary = summaryText;
overview = overviewText;
tasktype.value = 3;
}
Map taskFinishData = taskFinishList.firstWhere(
(element) => element['id'] == id,
orElse: () => {},
);
if (taskFinishData.isNotEmpty) {
taskFinishData['tasktype'] = 3;
taskFinishList.refresh();
}
_storage.write("meeting_task_finish_list", taskFinishList);
// 触发AI分析,分别请求总结和概览
_summaryTaskService.addTaskList(id, text, prompt, outline);
}
}

971
lib/data/services/meeting/meeting_task_service2.dart

@ -0,0 +1,971 @@
import 'dart:convert';
import 'dart:io';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:http/http.dart' as http;
import '../db/sqflite_api.dart';
import '../../../data/models/appconfig.dart';
import '../../../core/utils/logger.dart';
import '../../../core/utils/synchrodata.dart';
import '../usage_stats_service.dart';
import '../../../data/models/meeting_usage_stats.dart';
import '../deapsound_ai_service.dart';
import 'meeting_upload_service.dart';
// 移除标准版服务桥接,改为通过聚合器对外暴露统一状态
import 'summary_task_service.dart';
//火山引擎录音文件识别大模型-极速版
class MeetingTaskService2 extends GetxService {
final GetStorage _storage = GetStorage();
MeetingUploadService get _uploadService => Get.find<MeetingUploadService>();
SummaryTaskService get _summaryTaskService => Get.find<SummaryTaskService>();
List _taskList = [];
RxList taskFinishList = [].obs;
bool _isTask = false;
String _systemPrompt = '';
String _userId = '';
late final String _appid;
late final String _token;
late final String _serviceUrl;
int meetingId = 0;
RxInt tasktype = 1.obs;
List textList = [];
String summary = '';
String overview = '';
@override
void onInit() {
super.onInit();
_getAgent();
_getTaskList();
}
void _getAgent() async {
Map userInfo = _storage.read("user_info");
_userId = userInfo['user']['uid'];
_systemPrompt = AppConfig.isInitialized()
? (AppConfig.agentsystemPrompt("meet_assistant") ?? '')
: '';
final String base = AppConfig.env('VOLC_OPENSPEECH_BASE_URL_BIGMODEL') ??
'https://openspeech.bytedance.com/api/v3/auc/bigmodel';
_appid = AppConfig.env('VOLC_OPENSPEECH_APP_ID') ?? '';
_token = AppConfig.env('VOLC_OPENSPEECH_ACCESS_TOKEN') ?? '';
_serviceUrl =
base.endsWith('/recognize/flash') ? base : (base + '/recognize/flash');
}
void _getTaskList() {
_taskList = _storage.read("meeting_task_list_v2") ?? [];
taskFinishList.value = _storage.read("meeting_task_finish_list_v2") ?? [];
_executeTask();
}
Future<void> addTask(
int id,
String audiourl, {
bool isSpeaker = false,
String language = '',
String targetLanguage = '',
String prompt = '',
String outline = '',
}) async {
if (audiourl.isEmpty) {
Map uploadData = _uploadService.uploadList.firstWhere(
(element) => element['id'] == id,
orElse: () => {},
);
if (uploadData.isNotEmpty) {
if (uploadData['audiourl'].isEmpty) {
uploadData['isTask'] = true;
uploadData['template'] = {
'isSpeaker': isSpeaker,
'language': language,
'targetLanguage': targetLanguage,
'prompt': prompt,
'outline': outline,
};
_storage.write("meeting_upload_list", _uploadService.uploadList);
} else {
await addTaskList(
id,
uploadData['audiourl'],
isSpeaker: isSpeaker,
language: language,
targetLanguage: targetLanguage,
prompt: prompt,
outline: outline,
);
}
}
} else {
await addTaskList(
id,
audiourl,
isSpeaker: isSpeaker,
language: language,
targetLanguage: targetLanguage,
prompt: prompt,
outline: outline,
);
}
}
Future<void> addTaskList(
int id,
String audiourl, {
bool isSpeaker = false,
String language = '',
String targetLanguage = '',
String prompt = '',
String outline = '',
}) async {
final String taskId = DateTime.now().millisecondsSinceEpoch.toString();
await SqfliteApi.editMeeting(id, {'tasktype': 1, 'taskid': taskId});
try {
final detail = await SqfliteApi.getMeetingDetails(id);
final seconds = (detail['seconds'] ?? 0) as int;
final filepath = (detail['filepath'] ?? '') as String;
int fileSizeBytes = 0;
if (filepath.isNotEmpty) {
try {
fileSizeBytes = await File(filepath).length();
} catch (_) {}
}
final record = MeetingAsrRecord(
id: taskId,
meetingId: id,
taskId: taskId,
audioSeconds: seconds,
fileSizeBytes: fileSizeBytes,
language: language,
submitTimestamp: DateTime.now().millisecondsSinceEpoch,
status: asrStatusProcessing,
transcriptBytes: 0,
completeTimestamp: 0,
);
try {
final svc = Get.isRegistered<UsageStatsService>()
? Get.find<UsageStatsService>()
: Get.put(UsageStatsService(), permanent: true);
svc.addMeetingAsrRecord(record);
} catch (e) {
Logger.w('MeetingASRrecord', '提交用量记录失败: ' + e.toString());
}
} catch (_) {}
_taskList.add({
'id': id,
'audiourl': audiourl,
'tasktype': 1,
'taskid': taskId,
'template': {
'isSpeaker': isSpeaker,
'language': language,
'targetLanguage': targetLanguage,
'prompt': prompt,
'outline': outline,
},
});
taskFinishList.add({'id': id, 'tasktype': 1});
_storage.write("meeting_task_list_v2", _taskList);
_storage.write("meeting_task_finish_list_v2", taskFinishList);
// 由聚合器统一对外呈现状态,不直接写入标准版列表
_executeTask();
}
void _executeTask() async {
if (_isTask) return;
_isTask = true;
Logger.debug('开始执行任务,任务数量:${_taskList.length}');
while (_taskList.isNotEmpty) {
Logger.debug('任务循环执行,剩余任务:${_taskList.length}');
await Future.delayed(const Duration(seconds: 2));
// 创建任务列表的副本,避免在迭代过程中修改原列表
List tasksCopy = List.from(_taskList);
for (var element in tasksCopy) {
Logger.debug('处理任务:${element['id']},音频:${element['audiourl']}');
// 检查任务是否仍在列表中(可能已被其他地方移除)
if (_taskList.any((task) => task['id'] == element['id'])) {
try {
await _fileRecognize(element);
} catch (e) {
Logger.error('处理任务失败:${element['id']},错误:$e');
// 确保失败的任务被移除,避免无限循环
_taskList.removeWhere((task) => task['id'] == element['id']);
_storage.write("meeting_task_list_v2", _taskList);
// 更新任务状态为失败
await SqfliteApi.editMeeting(element['id'], {'tasktype': 0});
}
} else {
Logger.debug('任务 ${element['id']} 已从任务列表移除');
}
}
// 如果没有任务被处理,避免无限循环
if (_taskList.length == tasksCopy.length) {
Logger.warning('本次循环未处理任何任务,为避免无限执行终止循环');
break;
}
}
_isTask = false;
Logger.debug('任务执行完成,剩余任务:${_taskList.length}');
}
void removeTask(int id, {bool isDeleteTask = false}) {
Map taskFinishData = taskFinishList.firstWhere(
(element) => element['id'] == id,
orElse: () => {},
);
if (taskFinishData.isNotEmpty) {
if (isDeleteTask || taskFinishData['tasktype'] >= 3) {
taskFinishList.remove(taskFinishData);
_storage.write("meeting_task_finish_list_v2", taskFinishList);
}
}
if (isDeleteTask) {
_taskList.removeWhere((element) => element['id'] == id);
_storage.write("meeting_task_list_v2", _taskList);
}
}
Future<Map<String, dynamic>> _recognizeAudio(
String audiourl, {
bool enableSpeakerInfo = true,
String language = '',
String? requestIdOverride,
}) async {
String requestId =
requestIdOverride ?? DateTime.now().millisecondsSinceEpoch.toString();
// 为每次请求生成新的headers - 适配大模型极速版API
Map<String, String> requestHeaders = {
'X-Api-App-Key': _appid,
'X-Api-Access-Key': _token,
'X-Api-Resource-Id': 'volc.bigasr.auc_turbo',
'X-Api-Request-Id': requestId,
'X-Api-Sequence': '-1',
'Content-Type': 'application/json',
};
// 使用大模型极速版API的新请求格式
final Map<String, dynamic> requestPayload = {
"user": {"uid": _appid},
"audio": {"url": audiourl},
"request": {
"model_name": "bigmodel",
"enable_itn": true,
"enable_punc": true,
"enable_ddc": true,
"enable_speaker_info": enableSpeakerInfo,
"word_info": 1,
"show_utterances": true
}
};
if (language.isNotEmpty) {
requestPayload['request']['language'] = language;
}
final String requestBody = jsonEncode(requestPayload);
try {
// 记录请求详情
Logger.debug('API 请求地址:$_serviceUrl');
Logger.debug('API 请求头:$requestHeaders');
Logger.debug('API 请求体:$requestBody');
final response = await http.post(
Uri.parse(_serviceUrl),
headers: requestHeaders,
body: requestBody,
);
Logger.debug('API 响应状态码:${response.statusCode}');
Logger.debug('API 响应头:${response.headers}');
if (response.statusCode != 200) {
Logger.error('识别失败,状态码:${response.statusCode},响应体:${response.body}');
throw Exception('识别失败,状态码:${response.statusCode}');
}
final respDic = jsonDecode(response.body);
Logger.debug('识别接口响应:$respDic');
// 检查响应中是否包含资源相关信息
if (respDic.containsKey('resource_id') || respDic.containsKey('model')) {
Logger.debug('资源校验 - 使用的资源ID:volc.bigasr.auc_turbo');
Logger.debug(
'响应中的资源信息:${respDic['resource_id'] ?? respDic['model'] ?? '响应未包含'}');
}
return respDic;
} catch (e) {
Logger.error('识别请求异常:${e.toString()}');
rethrow;
}
}
String _getFileType(String path) {
List<String> array = path.split('.');
return array[array.length - 1];
}
int _parseTime(dynamic timeValue) {
if (timeValue == null) return 0;
if (timeValue is int) {
return timeValue;
} else if (timeValue is double) {
return timeValue.round();
} else if (timeValue is String) {
try {
double parsed = double.parse(timeValue);
return parsed.round();
} catch (e) {
Logger.error('时间值解析失败:$timeValue');
return 0;
}
} else {
Logger.error('未知的时间值类型:${timeValue.runtimeType},值:$timeValue');
return 0;
}
}
Future<void> _fileRecognize(Map item) async {
try {
Logger.debug('开始识别音频:${item['audiourl']}');
// 识别语言选取:若设置了目标输出语言且与录音语言一致,优先让ASR自动识别,避免错配
final String tplLang =
(((item['template'] ?? {})['language']) ?? '').toString();
final String tplTarget =
(((item['template'] ?? {})['targetLanguage']) ?? '').toString();
String asrLanguage = tplLang;
if (tplTarget.isNotEmpty && tplTarget == tplLang) {
asrLanguage = '';
}
var respDic = await _recognizeAudio(
item['audiourl'],
enableSpeakerInfo:
(((item['template'] ?? {})['isSpeaker']) ?? false) as bool,
language: asrLanguage,
requestIdOverride: (item['taskid'] ?? '').toString().isEmpty
? null
: (item['taskid'] ?? '').toString(),
);
Logger.debug('API 全量响应结构:${respDic.toString()}');
Logger.debug('响应包含的键:${respDic.keys.toList()}');
// 检查响应格式并提取utterances
List utterances = [];
// 检查不同可能的响应格式
if (respDic['result'] != null &&
respDic['result']['utterances'] != null) {
utterances = respDic['result']['utterances'];
Logger.debug('在 result.utterances 中找到 ${utterances.length} 条语句');
} else if (respDic['resp'] != null &&
respDic['resp']['utterances'] != null) {
utterances = respDic['resp']['utterances'];
Logger.debug('在 resp.utterances 中找到 ${utterances.length} 条语句');
} else if (respDic['utterances'] != null) {
utterances = respDic['utterances'];
Logger.debug('在根级 utterances 中找到 ${utterances.length} 条语句');
} else if (respDic['data'] != null &&
respDic['data']['utterances'] != null) {
utterances = respDic['data']['utterances'];
Logger.debug('在 data.utterances 中找到 ${utterances.length} 条语句');
} else if (respDic['response'] != null &&
respDic['response']['utterances'] != null) {
utterances = respDic['response']['utterances'];
Logger.debug('在 response.utterances 中找到 ${utterances.length} 条语句');
} else {
// 检查是否有错误信息
if (respDic['error'] != null) {
Logger.error('接口返回错误:${respDic['error']}');
} else if (respDic['message'] != null) {
Logger.error('接口返回消息:${respDic['message']}');
} else {
Logger.error('未知的响应格式。可用键:${respDic.keys.toList()}');
// 尝试查找任何包含文本的字段
respDic.forEach((key, value) {
Logger.debug('键:$key,值类型:${value.runtimeType},值:$value');
});
}
}
if (utterances.isNotEmpty) {
Logger.debug('开始处理 ${utterances.length} 条语句');
await _addTextList(item['id'], utterances, item['template']);
// 从任务列表中移除已完成的任务
_taskList.removeWhere((element) => element['id'] == item['id']);
_storage.write("meeting_task_list_v2", _taskList);
Logger.debug('音频识别成功,会议ID:${item['id']}');
// 更新UI状态 - 如果是当前会议,触发UI更新
if (item['id'] == meetingId) {
tasktype.value = 2; // 转写完成,进入分析阶段
}
} else {
Logger.error('响应中未发现语句。完整响应:$respDic');
Logger.debug('未检测到语句,开始执行无声音频检查');
Logger.debug('无声音频检测调试信息');
Logger.debug('响应键列表:${respDic.keys.toList()}');
Logger.debug('响应代码:${respDic['code']}');
Logger.debug('响应消息:${respDic['message']}');
// 检查是否为无声音频
bool isSilentAudio = _checkIfSilentAudio(respDic);
Logger.debug('无声检测结果:$isSilentAudio');
if (isSilentAudio) {
Logger.debug('检测到无声音频,设置任务类型为 -1');
// 设置无声音频状态 (使用特殊值 -1)
await SqfliteApi.editMeeting(item['id'], {'tasktype': -1});
if (item['id'] == meetingId) {
Logger.debug('当前会议设置 tasktype.value 为 -1');
tasktype.value = -1; // 无声音频
}
// 更新taskFinishList中的状态
Map taskFinishData = taskFinishList.firstWhere(
(element) => element['id'] == item['id'],
orElse: () => {},
);
if (taskFinishData.isNotEmpty) {
taskFinishData['tasktype'] = -1;
taskFinishList.refresh();
}
_storage.write("meeting_task_finish_list_v2", taskFinishList);
// 由聚合器统一对外呈现状态,不直接写入标准版列表
// 由聚合器统一对外呈现状态,不直接写入标准版列表
} else {
Logger.error('识别失败,原因未知');
// 识别失败,更新数据库状态为失败
await SqfliteApi.editMeeting(item['id'], {'tasktype': 0});
if (item['id'] == meetingId) {
tasktype.value = 0; // 识别失败
}
// 更新taskFinishList中的状态
Map taskFinishData = taskFinishList.firstWhere(
(element) => element['id'] == item['id'],
orElse: () => {},
);
if (taskFinishData.isNotEmpty) {
taskFinishData['tasktype'] = 0;
taskFinishList.refresh();
}
_storage.write("meeting_task_finish_list_v2", taskFinishList);
}
// 从任务列表中移除
_taskList.removeWhere((element) => element['id'] == item['id']);
_storage.write("meeting_task_list_v2", _taskList);
}
} catch (e) {
Logger.error('文件识别流程发生异常:${e.toString()}');
Logger.error('堆栈信息:${StackTrace.current}');
// 更新数据库状态为失败
try {
await SqfliteApi.editMeeting(item['id'], {'tasktype': 0});
} catch (dbError) {
Logger.error('数据库更新会议状态失败:$dbError');
}
// 出错时也要从任务列表中移除,避免无限重试
_taskList.removeWhere((element) => element['id'] == item['id']);
_storage.write("meeting_task_list_v2", _taskList);
// 更新UI状态 - 如果是当前会议,显示错误状态
if (item['id'] == meetingId) {
tasktype.value = 0; // 识别失败
}
}
}
/// 检查是否为无声音频
bool _checkIfSilentAudio(Map<String, dynamic> response) {
Logger.debug('检查是否为无声音频,响应:${response.toString()}');
// 检查API响应中的错误信息或状态码
// 根据实际API响应格式调整检测逻辑
// 检查是否有错误码表示无声音频
if (response['code'] != null) {
int code = response['code'];
Logger.debug('检测到响应代码:$code');
// 常见的无声音频错误码
if (code == 40001 ||
code == 40002 ||
code == 40003 ||
code == 50001 ||
code == 50002 ||
code == 50003) {
Logger.debug('根据错误码判断为无声音频:$code');
return true;
}
}
// 检查错误消息
if (response['message'] != null) {
String message = response['message'].toString().toLowerCase();
Logger.debug('检测到响应消息:$message');
if (message.contains('silent') ||
message.contains('no audio') ||
message.contains('无声') ||
message.contains('静音') ||
message.contains('empty audio') ||
message.contains('no speech') ||
message.contains('audio too short') ||
message.contains('insufficient audio')) {
Logger.debug('根据消息判断为无声音频:$message');
return true;
}
}
// 检查result中的错误信息
if (response['result'] != null && response['result']['error'] != null) {
String error = response['result']['error'].toString().toLowerCase();
Logger.debug('检测到 result.error:$error');
if (error.contains('silent') ||
error.contains('no audio') ||
error.contains('无声') ||
error.contains('静音') ||
error.contains('empty audio') ||
error.contains('no speech') ||
error.contains('audio too short')) {
Logger.debug('根据 result.error 判断为无声音频:$error');
return true;
}
}
// 检查是否有音频时长信息且时长为0或极短
if (response['result'] != null && response['result']['duration'] != null) {
double duration = (response['result']['duration'] as num).toDouble();
Logger.debug('检测到音频时长:$duration 秒');
if (duration <= 0.5) {
// 音频时长小于0.5秒认为是无声
Logger.debug('根据时长过短判断为无声音频:$duration');
return true;
}
}
// 检查utterances是否为空且没有其他明确的成功标识
bool hasUtterances = false;
if (response['result'] != null &&
response['result']['utterances'] != null) {
hasUtterances = (response['result']['utterances'] as List).isNotEmpty;
} else if (response['resp'] != null &&
response['resp']['utterances'] != null) {
hasUtterances = (response['resp']['utterances'] as List).isNotEmpty;
} else if (response['utterances'] != null) {
hasUtterances = (response['utterances'] as List).isNotEmpty;
} else if (response['data'] != null &&
response['data']['utterances'] != null) {
hasUtterances = (response['data']['utterances'] as List).isNotEmpty;
} else if (response['response'] != null &&
response['response']['utterances'] != null) {
hasUtterances = (response['response']['utterances'] as List).isNotEmpty;
}
// 检查文本内容是否为空
String textContent = '';
if (response['result'] != null && response['result']['text'] != null) {
textContent = response['result']['text'].toString().trim();
} else if (response['text'] != null) {
textContent = response['text'].toString().trim();
} else if (response['data'] != null && response['data']['text'] != null) {
textContent = response['data']['text'].toString().trim();
}
// 如果文本内容为空且音频时长大于1秒,很可能是无声音频
if (textContent.isEmpty) {
double audioDuration = 0;
if (response['audio_info'] != null &&
response['audio_info']['duration'] != null) {
audioDuration = (response['audio_info']['duration'] as num).toDouble() /
1000; // 转换为秒
} else if (response['result'] != null &&
response['result']['additions'] != null &&
response['result']['additions']['duration'] != null) {
audioDuration =
(response['result']['additions']['duration'] as num).toDouble() /
1000; // 转换为秒
}
Logger.debug('文本内容为空,音频时长:$audioDuration 秒');
if (audioDuration > 1.0) {
// 音频时长大于1秒但没有文本内容,认为是无声音频
Logger.debug('判断为无声音频:文本为空且时长充足');
return true;
}
}
// 如果没有utterances且响应状态正常,可能是无声音频
if (!hasUtterances) {
// 检查是否有明确的成功状态码
bool hasSuccessCode = false;
if (response['code'] != null) {
int code = response['code'];
hasSuccessCode = (code == 0 || code == 200);
}
// 如果有成功状态码但没有utterances,很可能是无声音频
if (hasSuccessCode) {
Logger.debug('判断为无声音频:成功状态码但无语句');
return true;
}
}
Logger.debug('未判定为无声音频');
return false;
}
Future<void> _addTextList(int id, List utterances,
[Map? templateData]) async {
Logger.debug('处理会议 $id 的 ${utterances.length} 条语句');
String text = '';
String personnel = '';
List<Map<String, Object?>> list = [];
for (int i = 0; i < utterances.length; i++) {
var element = utterances[i];
Logger.debug('处理第 $i 条语句:${element.toString()}');
String speaker = '';
String content = '';
int startTime = 0;
int endTime = 0;
// 提取说话人信息 - 检查多种可能的字段名
if (element['additions'] != null && element['additions'].isNotEmpty) {
if (element['additions']['speaker'] != null) {
speaker = 'Speaker ${element['additions']['speaker']}';
}
} else if (element['speaker'] != null) {
speaker = 'Speaker ${element['speaker']}';
} else if (element['speaker_id'] != null) {
speaker = 'Speaker ${element['speaker_id']}';
}
// 提取文本内容 - 检查多种可能的字段名
if (element['text'] != null) {
content = element['text'].toString();
} else if (element['content'] != null) {
content = element['content'].toString();
} else if (element['transcript'] != null) {
content = element['transcript'].toString();
} else {
Logger.error('语句中未找到文本内容:$element');
continue;
}
// 提取时间信息 - 检查多种可能的字段名和格式
if (element['start_time'] != null) {
startTime = _parseTime(element['start_time']);
} else if (element['startTime'] != null) {
startTime = _parseTime(element['startTime']);
} else if (element['begin'] != null) {
startTime = _parseTime(element['begin']);
}
if (element['end_time'] != null) {
endTime = _parseTime(element['end_time']);
} else if (element['endTime'] != null) {
endTime = _parseTime(element['endTime']);
} else if (element['end'] != null) {
endTime = _parseTime(element['end']);
}
if (speaker.isNotEmpty) {
text += '[$speaker]: ';
if (!personnel.contains(speaker)) {
personnel += '[$speaker] ';
}
}
list.add({
'meetingid': id,
'content': content,
'starttime': startTime,
'endtime': endTime,
'speaker': speaker,
});
text += '$content\n';
Logger.debug('已添加语句:说话人=$speaker,内容=$content,开始=$startTime,结束=$endTime');
}
Logger.debug('处理完成的语句总数:${list.length}');
var result = await SqfliteApi.insertMeetingSpeaker(list);
if (result != null) {
// 初始用于总结/概览的文本,先用原始拼接文本作为默认值
String summarySourceText = text;
// 根据目标语言决定是否需要翻译文本列表
final String targetLanguage =
((templateData?['targetLanguage']) ?? '').toString();
final String sourceLanguage =
((templateData?['language']) ?? '').toString();
bool needTranslate = false;
if (targetLanguage.isNotEmpty) {
// 若未指定录音语言,默认认为需要翻译;否则当目标语言与录音语言主码不同则翻译
if (sourceLanguage.isEmpty) {
needTranslate = true;
} else {
String srcPrefix = sourceLanguage.toLowerCase().substring(0, 2);
String tgtPrefix = targetLanguage.toLowerCase().substring(0, 2);
needTranslate = srcPrefix != tgtPrefix;
}
}
if (needTranslate) {
try {
// 保持在“正在转写”状态,先进行翻译为目标语言
await _translateTextList(id, targetLanguage);
} catch (e) {
Logger.error('转写文本翻译失败:${e.toString()}');
}
// 翻译完成后再写入 personnel、设置已完成并刷新 UI
await SqfliteApi.editMeeting(
id, {'tasktype': 2, 'personnel': personnel});
List speakerList = await SqfliteApi.getMeetingSpeaker(id);
List newSpeakerList = List.from(speakerList);
Synchrodata.saveOperationRecord('update', {
'original': jsonEncode(newSpeakerList),
'id': id,
});
if (id == meetingId) {
textList = newSpeakerList;
tasktype.value = 2;
}
// 由聚合器统一对外呈现状态,不直接写入标准版列表
// 由聚合器统一对外呈现状态,不直接写入标准版列表
// 用最新(已翻译)的文本重建总结/概览输入
summarySourceText = '';
for (var element in newSpeakerList) {
final String spk = (element['speaker'] ?? '').toString();
final String cnt = (element['content'] ?? '').toString();
if (spk.isNotEmpty) {
summarySourceText += '[$spk]: ';
}
summarySourceText += '$cnt\n';
}
Map taskFinishData = taskFinishList.firstWhere(
(element) => element['id'] == id,
orElse: () => {},
);
if (taskFinishData.isNotEmpty) {
taskFinishData['tasktype'] = 2;
taskFinishList.refresh();
}
_storage.write("meeting_task_finish_list_v2", taskFinishList);
} else {
// 原有中文直出流程
await SqfliteApi.editMeeting(
id, {'tasktype': 2, 'personnel': personnel});
List speakerList = await SqfliteApi.getMeetingSpeaker(id);
List newSpeakerList = List.from(speakerList);
Synchrodata.saveOperationRecord('update', {
'original': jsonEncode(newSpeakerList),
'id': id,
});
if (id == meetingId) {
textList = newSpeakerList;
tasktype.value = 2;
}
// 仍使用最新DB中的文本构建总结/概览输入,避免与原始拼接文本不一致
summarySourceText = '';
for (var element in newSpeakerList) {
final String spk = (element['speaker'] ?? '').toString();
final String cnt = (element['content'] ?? '').toString();
if (spk.isNotEmpty) {
summarySourceText += '[$spk]: ';
}
summarySourceText += '$cnt\n';
}
Map taskFinishData = taskFinishList.firstWhere(
(element) => element['id'] == id,
orElse: () => {},
);
if (taskFinishData.isNotEmpty) {
taskFinishData['tasktype'] = 2;
taskFinishList.refresh();
}
_storage.write("meeting_task_finish_list_v2", taskFinishList);
}
// 使用统一的总结服务生成概览与总结
final String tplPrompt = ((templateData?['prompt']) ?? '').toString();
final String tplOutline = ((templateData?['outline']) ?? '').toString();
final String outCode = (((templateData?['targetLanguage']) ??
(templateData?['language']) ??
'') as String)
.toLowerCase();
String langDesc = '';
if (outCode.startsWith('zh')) {
langDesc = '中文';
} else if (outCode.startsWith('en')) {
langDesc = '英文';
} else if (outCode.startsWith('ja')) {
langDesc = '日文';
} else if (outCode.startsWith('ko')) {
langDesc = '韩文';
} else if (outCode.startsWith('fr')) {
langDesc = '法文';
} else if (outCode.startsWith('de')) {
langDesc = '德文';
} else if (outCode.startsWith('es')) {
langDesc = '西班牙文';
} else if (outCode.startsWith('ru')) {
langDesc = '俄文';
} else if (outCode.startsWith('it')) {
langDesc = '意大利文';
} else if (outCode.startsWith('pt')) {
langDesc = '葡萄牙文';
} else if (outCode.startsWith('th')) {
langDesc = '泰文';
} else if (outCode.startsWith('vi')) {
langDesc = '越南文';
}
final String promptToUse = tplPrompt.isEmpty
? (langDesc.isEmpty
? ''
: '输出语言:' + langDesc + '。请全程使用' + langDesc + '输出。')
: (langDesc.isEmpty
? tplPrompt
: tplPrompt + ' 输出语言:' + langDesc + '。请全程使用' + langDesc + '输出。');
final String outlineToUse = tplOutline.isEmpty
? (langDesc.isEmpty
? ''
: '输出语言:' + langDesc + '。请全程使用' + langDesc + '输出。')
: (langDesc.isEmpty
? tplOutline
: tplOutline + ' 输出语言:' + langDesc + '。请全程使用' + langDesc + '输出。');
try {
final details = await SqfliteApi.getMeetingDetails(id);
final tid = (details['taskid'] ?? '') as String;
final transcriptBytes = utf8.encode(summarySourceText).length;
final svc = Get.isRegistered<UsageStatsService>()
? Get.find<UsageStatsService>()
: Get.put(UsageStatsService(), permanent: true);
svc.completeMeetingAsrRecord(
id: tid,
transcriptBytes: transcriptBytes,
completeTimestamp: DateTime.now().millisecondsSinceEpoch,
);
} catch (e) {
Logger.w('MeetingASRrecord', '完成用量记录失败: ' + e.toString());
}
_summaryTaskService.addTaskList(
id, summarySourceText, promptToUse, outlineToUse);
}
}
Future<void> _translateTextList(int id, String targetLanguage) async {
// 读取刚插入的文本条目
List speakerList = await SqfliteApi.getMeetingSpeaker(id);
// 构造简洁的可翻译列表
List toTranslate = speakerList
.map((e) => {
'id': e['id'],
'speaker': (e['speaker'] ?? '').toString(),
'content': (e['content'] ?? '').toString(),
})
.toList();
final String userJson = jsonEncode({
'targetLanguage': targetLanguage,
'items': toTranslate,
});
// 根据目标语言构建提示语
String tgtName = targetLanguage.toLowerCase();
String langDesc = '目标语言';
if (tgtName.startsWith('zh')) {
langDesc = '中文';
} else if (tgtName.startsWith('en')) {
langDesc = '英文';
} else if (tgtName.startsWith('ja')) {
langDesc = '日文';
} else if (tgtName.startsWith('ko')) {
langDesc = '韩文';
} else if (tgtName.startsWith('fr')) {
langDesc = '法文';
} else if (tgtName.startsWith('de')) {
langDesc = '德文';
} else if (tgtName.startsWith('es')) {
langDesc = '西班牙文';
} else if (tgtName.startsWith('ru')) {
langDesc = '俄文';
} else if (tgtName.startsWith('it')) {
langDesc = '意大利文';
} else if (tgtName.startsWith('pt')) {
langDesc = '葡萄牙文';
} else if (tgtName.startsWith('th')) {
langDesc = '泰文';
} else if (tgtName.startsWith('vi')) {
langDesc = '越南文';
}
final String systemPrompt = '你是专业的翻译助手。请将每条items中的content精准翻译为' +
langDesc +
',保持术语专业、语气自然。仅返回JSON数组,元素形如{"id":<原id>,"content":"<翻译后文本>"},不要额外说明,不要漏掉任何一条。';
final String? translated = await DeapsoundAIService().sendMessage(
messages: [
{'role': 'system', 'content': systemPrompt},
{'role': 'user', 'content': userJson},
],
);
if (translated == null || translated.isEmpty) return;
List<dynamic> arr;
try {
arr = jsonDecode(translated);
} catch (_) {
// 若模型返回包裹对象,尝试取字段
try {
final obj = jsonDecode(translated);
arr = (obj is Map && obj['data'] is List) ? (obj['data'] as List) : [];
} catch (e) {
Logger.error('翻译结果 JSON 解析失败:${e.toString()}');
return;
}
}
if (arr.isEmpty) return;
// 批量更新
for (var item in arr) {
if (item is Map && item['id'] != null) {
await SqfliteApi.editMeetingSpeaker([
{
'id': item['id'],
'content': (item['content'] ?? '').toString(),
}
]);
}
}
// 刷新缓存
if (id == meetingId) {
textList = await SqfliteApi.getMeetingSpeaker(id);
// 主动触发监听刷新 UI(MeetingDetailsController 通过监听 tasktype 同步 textList)
try {
tasktype.refresh();
} catch (_) {}
}
}
}

82
lib/data/services/meeting/meeting_upload_service.dart

@ -1,11 +1,15 @@
import 'dart:io';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import '../../../core/utils/logger.dart';
import '../../../core/utils/upload_oss.dart';
import '../usage_stats_service.dart';
import '../db/sqflite_api.dart';
import 'meeting_task_service.dart';
import 'meeting_task_service2.dart';
/// 管理会议音频文件上传服务
class MeetingUploadService extends GetxService {
final _taskService = Get.find<MeetingTaskService>();
@ -16,7 +20,7 @@ class MeetingUploadService extends GetxService {
RxList uploadList = [].obs;
bool _isUpload = false;
int _handled = 0;
int _handled = 0; //队列处理指针,表示当前循环语句处理的任务数量
@override
void onInit() {
@ -24,6 +28,13 @@ class MeetingUploadService extends GetxService {
_getUploadList();
}
void cancelUpload() {
_isUpload = false;
_handled = 0;
uploadList.clear();
_storage.remove("meeting_upload_list");
}
void _getUploadList() {
uploadList.value = _storage.read("meeting_upload_list") ?? [];
executeUpload();
@ -36,6 +47,15 @@ class MeetingUploadService extends GetxService {
String rootDir, {
bool isUpload = true,
}) async {
bool flash = false;
int fileSize = 0;
try {
fileSize = await File(filePath).length(); //获取文件大小
final details = await SqfliteApi.getMeetingDetails(id);
final int seconds = (details['seconds'] ?? 0) as int;
flash = seconds > 0 && seconds <= 7200;
} catch (_) {}
_storage.write("meeting_service_type_$id", flash ? 'fast' : 'standard');
uploadList.add({
'id': id,
'filepath': filePath,
@ -46,6 +66,8 @@ class MeetingUploadService extends GetxService {
'language': '',
'prompt': '',
'outline': '',
'useFlashASR': flash,
'fileSizeBytes': fileSize,
});
_storage.write("meeting_upload_list", uploadList);
if (isUpload) {
@ -63,27 +85,65 @@ class MeetingUploadService extends GetxService {
if (element['audiourl'].isEmpty) {
meetingId.value = element['id'];
try {
int _sent = 0;
int _total = 0;
final audiourl = await UploadOss.upload(
filepath: element['filepath'],
rootDir: element['rootdir'],
onSendProgress: (int count, int total) {
uploadProgress.value = count / total;
// uploadProgress.value = count / total;
_sent = count;
_total = total;
uploadProgress.value = total > 0 ? count / total : 0.0;
},
);
await SqfliteApi.editMeetingTitle(
element['id'],
{'audiourl': audiourl},
);
if (element['isTask']) {
await _taskService.addTaskList(
element['id'],
audiourl,
'',
element['isSpeaker'],
element['language'],
element['prompt'],
element['outline'],
try {
// 记录对象存储用量
final svc = Get.isRegistered<UsageStatsService>()
? Get.find<UsageStatsService>()
: Get.put(UsageStatsService(), permanent: true);
int fileSizeBytes = 0;
try {
fileSizeBytes = element['fileSizeBytes'] ?? 0;
} catch (_) {}
final transferred = _total > 0 ? _total : fileSizeBytes;
svc.recordMeetingObjectStorage(
meetingId: element['id'],
storageUrl: audiourl,
storageBytes: fileSizeBytes,
transferBytes: transferred,
uploadTimestamp: DateTime.now().millisecondsSinceEpoch,
);
} catch (e) {
Logger.w('MeetingOSrecord', '对象存储用量记录失败: ' + e.toString());
}
if (element['isTask']) {
if (element['useFlashASR'] == true) {
final service2 = Get.find<MeetingTaskService2>();
await service2.addTaskList(
element['id'],
audiourl,
isSpeaker: element['isSpeaker'],
language: element['language'],
targetLanguage: '',
prompt: element['prompt'],
outline: element['outline'],
);
} else {
await _taskService.addTaskList(
element['id'],
audiourl,
'',
element['isSpeaker'],
element['language'],
element['prompt'],
element['outline'],
);
}
}
element['audiourl'] = audiourl;
uploadProgress.value = 0.0;

187
lib/data/services/meeting/summary_task_service.dart

@ -0,0 +1,187 @@
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import '../../../core/utils/logger.dart';
import '../db/sqflite_api.dart';
import '../deapsound_ai_service.dart';
import 'meeting_task_service.dart';
import 'meeting_task_service2.dart';
class SummaryTaskService extends GetxService {
final _taskService = Get.find<MeetingTaskService>();
final _taskService2 = Get.find<MeetingTaskService2>();
final GetStorage _storage = GetStorage();
List _taskList = [];
bool _isTask = false;
String summary = ''; //AI总结内容
String overview = ''; //AI概览内容
@override
void onInit() {
super.onInit();
_getTaskList();
}
void cancelTask() {
_taskList.clear();
_storage.remove("summary_task_list");
}
void _getTaskList() {
_taskList = _storage.read("summary_task_list") ?? [];
_executeTask();
}
Future<void> addTaskList(
int id, String text, String prompt, String outline) async {
Logger.debug("添加总结任务列表");
_taskList.add({
'id': id,
'text': text,
'prompt': prompt,
'outline': outline,
});
_storage.write("summary_task_list", _taskList);
_executeTask();
}
void _executeTask() async {
if (_taskList.isEmpty) return;
if (_isTask) return;
_isTask = true;
var task = _taskList.first;
_aiServiceMessage(
task['id'],
task['text'],
task['prompt'],
task['outline'],
);
Logger.debug("执行总结任务列表");
}
void removeTask(int id) {
_taskList.removeWhere((element) => element['id'] == id);
_storage.write("summary_task_list", _taskList);
}
void _aiServiceMessage(int id, String text, String prompt, String outline) {
final ai = DeapsoundAIService();
String summaryText = '';
String overviewText = '';
var summaryDone = false;
var overviewDone = false;
var summarySuccess = false;
var overviewSuccess = false;
void tryFinish() {
if (summaryDone && overviewDone) {
if (summarySuccess &&
overviewSuccess &&
summaryText.isNotEmpty &&
overviewText.isNotEmpty) {
_aiServiceValue(id, summaryText, overviewText);
} else {
_isTask = false;
_executeTask();
}
}
}
final summaryStream = ai.sendMessageStream(messages: [
{'role': 'system', 'content': prompt},
{'role': 'user', 'content': text},
]).timeout(const Duration(seconds: 120));
final overviewStream = ai.sendMessageStream(messages: [
{'role': 'system', 'content': outline},
{'role': 'user', 'content': text},
]).timeout(const Duration(seconds: 120));
summaryStream.listen((chunk) {
summaryText += chunk;
}, onError: (error) {
summaryDone = true;
summarySuccess = false;
tryFinish();
}, onDone: () {
summaryDone = true;
summarySuccess = true;
tryFinish();
}, cancelOnError: true);
overviewStream.listen((chunk) {
overviewText += chunk;
}, onError: (error) {
overviewDone = true;
overviewSuccess = false;
tryFinish();
}, onDone: () {
overviewDone = true;
overviewSuccess = true;
tryFinish();
}, cancelOnError: true);
}
Future<void> _aiServiceValue(
int id, String summaryText, String overviewText) async {
final exists = _taskList.any((item) => item['id'] == id);
if (!exists) {
_isTask = false;
_executeTask();
return;
}
await SqfliteApi.editMeeting(id, {
'tasktype': 3,
'summary': summaryText,
'overview': overviewText,
});
// 更新 V1 Service 状态
if (id == _taskService.meetingId) {
summary = summaryText;
overview = overviewText;
_taskService.tasktype.value = 3;
}
// 更新 V2 Service 状态
if (id == _taskService2.meetingId) {
summary = summaryText;
overview = overviewText;
_taskService2.summary = summaryText;
_taskService2.overview = overviewText;
_taskService2.tasktype.value = 3;
}
// 更新 V1 任务完成列表
Map taskFinishData = _taskService.taskFinishList.firstWhere(
(element) => element['id'] == id,
orElse: () => {},
);
if (taskFinishData.isNotEmpty) {
taskFinishData['tasktype'] = 3;
_taskService.taskFinishList.refresh();
}
_storage.write("meeting_task_finish_list", _taskService.taskFinishList);
// 更新 V2 任务完成列表
Map taskFinishData2 = _taskService2.taskFinishList.firstWhere(
(element) => element['id'] == id,
orElse: () => {},
);
if (taskFinishData2.isNotEmpty) {
taskFinishData2['tasktype'] = 3;
_taskService2.taskFinishList.refresh();
}
_storage.write("meeting_task_finish_list_v2", _taskService2.taskFinishList);
_taskList.removeWhere((element) => element['id'] == id);
_storage.write("summary_task_list", _taskList);
_isTask = false;
_executeTask();
Logger.debug("总结任务完成");
}
}

64
lib/data/services/network/api.dart

@ -136,6 +136,15 @@ class Api {
);
}
//获取所有渠道包信息
static getChannelApps() {
return DioManager().request(
NWMethod.post,
'/api/home/user_getchannelapps',
//params: params,
);
}
//绑定设备
static binddevice([params]) {
return DioManager().request(
@ -181,6 +190,15 @@ class Api {
);
}
//询问订单
static payverifyorder([params]) {
return DioManager().request(
NWMethod.post,
'/api/home/pay_verifyorder',
params: params,
);
}
//获取模版数据
static getEchomeetTemplates([params]) {
return DioManager().request(
@ -217,11 +235,51 @@ class Api {
);
}
//获取唤醒词
static getwakeupvoices([params]) {
//获取商品列表
static getGoods([params]) {
return DioManager().request(
NWMethod.post,
'/api/home/pay_getgoodss',
params: params,
);
}
/// 资源使用/用量上报接口(`/api/home/user_usages`)
///
/// 用途:上报翻译(Translation)和会议(Meet)的用量,服务端据此统计并回传最新余额/积分。
///
/// 当前在 Dart 侧的使用场景:
/// - 会议助手 ASR:`UsageStatsService._reportMeetingUsageToServer`
/// - 翻译/同传 ASR:`UsageStatsService._reportAsrUsageToServer`
///
/// 参数(`params`)结构:
/// - `usagetype`:`int` 类型,使用场景类型(对应 `UsageType.toInt`),目前仅使用:
/// - `1`:翻译(Translation)
/// - `2`:会议(Meet)
/// - `usages`:`Map<String, int>`,各项指标的键值对,例如:
/// - `MEETING_ASR_AUDIO_SECONDS`:会议识别音频时长(秒)
/// - `TRANSLATION_MODE_{mode}`:某翻译模式下累计有效识别秒数
/// - `TRANSLATION_ASR_LANGUAGE_{language}`:某语言/语言对下的调用次数
///
/// 返回:
/// - 经过 `AuthInterceptor` 处理后,本方法返回值即为服务端响应体中的 `data` 字段。
/// - 若上报成功,`data['usages']` 为 `Map<String, int>`,内部各键的含义与积分/余额更新规则由服务端约定。
///
/// 使用示例(Dart):
/// ```dart
/// final params = {
/// 'usagetype': UsageType.Meet.toInt,
/// 'usages': {
/// 'MEETING_ASR_AUDIO_SECONDS': 120,
/// }
/// };
/// final data = await Api.usagesResPoints(params);
/// final usages = (data['usages'] as Map?)?.cast<String, dynamic>();
/// ```
static usagesResPoints([params]) {
return DioManager().request(
NWMethod.post,
'/api/home/user_getwakeupvoices',
'/api/home/user_usages',
params: params,
);
}

13
lib/data/services/network/auth_interceptor.dart

@ -1,20 +1,33 @@
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart' hide Response;
import 'dart:convert';
import 'package:crypto/crypto.dart';
import 'package:get_storage/get_storage.dart';
import 'entity/base_entity.dart';
class AuthInterceptor extends Interceptor {
final GetStorage _storage = GetStorage();
final String _signKey = '@214%67g15q4*67m17#4l67!'; // 替换为实际的密钥
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
var jsonString = _storage.read<String>("logintoken");
options.headers['Authorization'] = jsonString;
final timestamp = DateTime.now().millisecondsSinceEpoch.toString();
options.headers['Ts'] = timestamp;
options.headers['Sign'] = _generateSign(timestamp);
handler.next(options);
}
String _generateSign(String timestamp) {
// 按照“MD5(私钥 + 时间戳)”生成签名,与 Go 端保持一致
final signStr = 'ts=${timestamp}key=${_signKey}';
print("signStr: $signStr");
return md5.convert(utf8.encode(signStr)).toString();
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) async {
BaseEntity entity = BaseEntity.fromJson(response.data);

16
lib/data/services/network/dio_manager.dart

@ -14,9 +14,9 @@ class DioManager {
String get baseUrl {
final countryCode = Get.deviceLocale?.countryCode?.toUpperCase();
final isChinaMainland = countryCode == 'CN';
if (!isChinaMainland) {
return dotenv.env['HW_SERVER_URL'] ?? dotenv.env['SERVER_URL'] ?? '';
final channel = dotenv.env['Channel'] ?? 'OFFICIAL';
if (!isChinaMainland || channel == "GLOBAL_GOOGLE") {
return dotenv.env['HW_SERVER_URL'] ?? '';
} else {
return dotenv.env['SERVER_URL'] ?? '';
}
@ -34,6 +34,16 @@ class DioManager {
dio = Dio(options);
dio.interceptors.add(AuthInterceptor());
// 调试:输出请求与响应的详细日志,便于排查服务端创建订单或查询订单问题
dio.interceptors.add(LogInterceptor(
request: true,
requestHeader: true,
requestBody: true,
responseHeader: false,
responseBody: true,
error: true,
logPrint: (obj) => print('[DIO] $obj'),
));
}
// 请求,返回参数为 T

55
lib/data/services/novice_guide_service.dart

@ -23,10 +23,10 @@ class NoviceGuideService extends GetxService {
List aiStepsList = [
{
'start': '对小言说:“今天天气怎么样”',
'input': '今天天气怎么样',
'send': '小言会为你实时为你播报天气',
'end': '小言能实时为你播报天气,试试其他指令吧',
'startKey': 'guideWeatherStart',
'inputKey': 'guideWeatherInput',
'sendKey': 'guideWeatherSend',
'endKey': 'guideWeatherEnd',
'method': () async {
// 天气查询需要位置权限
await PermissionUtil.instance.requestPermission(
@ -39,17 +39,17 @@ class NoviceGuideService extends GetxService {
},
},
{
'start': '对小言说:“请播放一组摇滚乐”',
'input': '请播放一组摇滚乐',
'send': '小言会为你搜寻到一组音乐',
'end': '小言已成功为您搜寻到一组音乐,试试其他指令吧',
'startKey': 'guideMusicStart',
'inputKey': 'guideMusicInput',
'sendKey': 'guideMusicSend',
'endKey': 'guideMusicEnd',
'method': () async {},
},
{
'start': '对小言说:“导航到深圳机场”',
'input': '导航到深圳机场',
'send': '小言会为你规划路线',
'end': '小言已成功为您导航到深圳机场,试试其他指令吧',
'startKey': 'guideNavStart',
'inputKey': 'guideNavInput',
'sendKey': 'guideNavSend',
'endKey': 'guideNavEnd',
'method': () async {
// 导航功能需要位置权限
await PermissionUtil.instance.requestPermission(
@ -62,10 +62,10 @@ class NoviceGuideService extends GetxService {
},
},
{
'start': '对小言说:“明天下午3点创建会议提醒”',
'input': '明天下午3点创建会议提醒',
'send': '小言会为你创建会议提醒',
'end': '小言已成功为您创建会议提醒,试试其他指令吧',
'startKey': 'guideMeetingStart',
'inputKey': 'guideMeetingInput',
'sendKey': 'guideMeetingSend',
'endKey': 'guideMeetingEnd',
'method': () async {
//创建会议提醒需要日历权限
await PermissionUtil.instance.requestPermission(
@ -78,10 +78,10 @@ class NoviceGuideService extends GetxService {
},
},
{
'start': '对小言说:“拨打妈妈的电话”',
'input': '拨打妈妈的电话',
'send': '小言会为你拨打电话',
'end': '小言已成功为您拨打电话,试试其他指令吧',
'startKey': 'guidePhoneStart',
'inputKey': 'guidePhoneInput',
'sendKey': 'guidePhoneSend',
'endKey': 'guidePhoneEnd',
'method': () async {
if (Platform.isAndroid) {
// 拨打电话需要电话权限
@ -103,19 +103,12 @@ class NoviceGuideService extends GetxService {
},
},
{
'start': '对小言说:“给爸爸发短信说晚上回家吃饭’”',
'input': '给爸爸发短信说晚上回家吃饭’',
'send': '小言会为你发送短信',
'end': '短信已发送,语音操控更便捷',
'startKey': 'guideSmsStart',
'inputKey': 'guideSmsInput',
'sendKey': 'guideSmsSend',
'endKey': 'guideSmsEnd',
'method': () async {
if (Platform.isAndroid) {
// 发送短信需要短信权限
await PermissionUtil.instance.requestPermission(
permissionType: Permission.sms,
permissionName: 'sms'.tr, // 短信
explanationText: 'smsPermissionDesc'.tr, // 用于发送短信功能
permanentDenialText: 'smsPermissionDetailDesc'.tr, // 发送短信功能需要短信权限
);
//发送短信还需要联系人权限
await PermissionUtil.instance.requestPermission(
permissionType: Permission.contacts,

18
lib/data/services/ota_check_service.dart

@ -57,6 +57,7 @@ class OtaCheckService extends GetxService {
/// [isFullyConnected] 设备是否完全连接
/// 返回是否成功执行了检查
Future<bool> performOtaCheck(bool isFullyConnected) async {
bool isForceUpdate = false;
try {
// 检查是否应该进行OTA检查
if (!shouldCheckOta()) {
@ -95,7 +96,12 @@ class OtaCheckService extends GetxService {
_otaCoreService.isNewVersionAvailable(currentVersion, latestVersion);
if (hasUpdate) {
Logger.d(_tag, '发现新版本,准备显示升级提醒');
isForceUpdate = latestInfo['isForceUpdate'] as bool? ?? false;
if (isForceUpdate) {
Logger.d(_tag, '发现强制更新版本,准备显示升级提醒');
} else {
Logger.d(_tag, '发现新版本,准备显示升级提醒');
}
// 再次确认当前在Home页面(防止异步执行期间页面切换)
if (_isCurrentlyOnHomePage()) {
@ -109,12 +115,18 @@ class OtaCheckService extends GetxService {
}
// 标记为已检查(无论是否有更新都标记为已检查)
_markAsChecked();
if (!isForceUpdate) {
_markAsChecked();
}
_isCheckingInProgress = false;
return true;
} catch (e) {
Logger.e(_tag, '检查OTA升级失败: $e');
// 即使检查失败,也标记为已检查,避免重复尝试
_markAsChecked();
if (!isForceUpdate) {
_markAsChecked();
}
_isCheckingInProgress = false;
return false;
}
}

821
lib/data/services/pay_service.dart

@ -1,6 +1,17 @@
import 'dart:async';
import 'dart:convert';
import 'package:agent_service/agent_service.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import '/data/services/network/api.dart';
import 'package:tobias/tobias.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:in_app_purchase_android/in_app_purchase_android.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import '../../data/models/user_Info.dart';
import '../../modules/login/controllers/weixinLogin.dart';
@ -10,6 +21,17 @@ typedef PaymentResultCallback = void Function(bool success, String message);
class PayService extends GetxService {
late FlWX _flwx;
late Tobias _tobias; // 添加 Tobias 实例
String? _lastOrderId; // 最近一次创建的订单号
// 内购
final InAppPurchase _inAppPurchase = InAppPurchase.instance;
StreamSubscription<List<PurchaseDetails>>? _iapSubscription;
final RxBool iapAvailable = false.obs;
PaymentResultCallback? _iapOnResult;
// 最近一次 IAP 购买上下文,用于主动查询时携带验证参数
PurchaseDetails? _lastIapPurchase;
ProductDetails? _lastIapProduct;
String? get lastOrderId => _lastOrderId;
@override
void onInit() {
@ -28,12 +50,13 @@ class PayService extends GetxService {
// 初始化支付宝SDK
_tobias = Tobias(); // 初始化 Tobias 实例
_initAlipay();
_initIAP();
}
/// 初始化支付宝SDK
Future<void> _initAlipay() async {
try {
// 检查支付宝是否安装 - 修复用法
// 检查支付宝是否安x装 - 修复用法
final isInstalled = await _tobias.isAliPayInstalled;
print('支付宝是否安装: $isInstalled');
} catch (e) {
@ -41,6 +64,443 @@ class PayService extends GetxService {
}
}
/// 初始化内购(Apple/Google)
Future<void> _initIAP() async {
try {
// Web 环境不支持内购
if (kIsWeb) {
iapAvailable.value = false;
return;
}
final available = await _inAppPurchase.isAvailable();
iapAvailable.value = available;
if (!available) return;
// 监听购买结果流
_iapSubscription?.cancel();
_iapSubscription = _inAppPurchase.purchaseStream.listen(
_handlePurchaseUpdates,
onDone: () => _iapSubscription?.cancel(),
onError: (e) {
_iapOnResult?.call(false, '内购异常: $e');
},
);
} catch (e) {
print('初始化内购失败: $e');
}
}
/// 调试:批量查询并打印内购商品详情(用于确认商品ID是否存在)
Future<void> debugQueryProducts(Set<String> productIds) async {
try {
// 先原样打印传入的 productIds,便于核对入参
print('[IAP] debugQueryProducts 输入 IDs(Set): $productIds');
final idsList = productIds.toList();
print('[IAP] debugQueryProducts 输入 IDs(List): ${idsList.join(', ')}');
for (final id in productIds) {
print('[IAP] 待查询商品ID: $id');
}
// 仅在非 Web 平台执行;平台信息用于日志
final platform = _platformString();
if (!iapAvailable.value) {
final available = await _inAppPurchase.isAvailable();
iapAvailable.value = available;
}
if (!iapAvailable.value) {
print('[IAP-$platform] 当前平台内购不可用,无法查询商品。');
return;
}
print('[IAP-$platform] 开始查询商品,IDs=${productIds.join(', ')}');
final resp = await _inAppPurchase.queryProductDetails(productIds);
if (resp.error != null) {
final err = resp.error!;
print(
'[IAP-$platform] 查询错误: code=${err.code}, source=${err.source}, message=${err.message}, details=${err.details}');
}
if (resp.productDetails.isEmpty) {
print('[IAP-$platform] 未返回任何商品。notFound=${resp.notFoundIDs}');
} else {
for (final p in resp.productDetails) {
print(
'[IAP-$platform] 商品: id=${p.id}, title=${p.title}, price=${p.price}, currency=${p.currencyCode}');
}
if (resp.notFoundIDs.isNotEmpty) {
print('[IAP-$platform] 未找到的IDs: ${resp.notFoundIDs}');
}
}
} catch (e) {
print('[IAP] 调试查询异常: $e');
}
}
Future<ProductDetails?> _queryIapProduct(String productId) async {
try {
final pid = productId.trim();
print('[IAP] 开始查询单个商品: id="$pid"');
final resp = await _inAppPurchase.queryProductDetails({pid});
if (resp.error != null) {
final err = resp.error!;
print(
'[IAP] 查询商品失败: code=${err.code}, source=${err.source}, message=${err.message}, details=${err.details}');
}
if (resp.productDetails.isEmpty) {
print('[IAP] 查询结果为空。notFound=${resp.notFoundIDs}');
return null;
}
for (final p in resp.productDetails) {
print(
'[IAP] 命中商品: id=${p.id}, title=${p.title}, price=${p.price}, currency=${p.currencyCode}');
}
// 避免 Dart 泛型推断在 Android 平台出现 orElse 类型不匹配(ProductDetails vs GooglePlayProductDetails)
ProductDetails? matched;
for (final p in resp.productDetails) {
if (p.id == pid) {
matched = p;
break;
}
}
return matched ?? resp.productDetails.first;
} catch (e) {
print('[IAP] 查询内购商品异常: $e');
return null;
}
}
/// Apple/Google 内购统一流程(消耗型)
Future<bool> _processIapPayment({
required String productId,
PaymentResultCallback? onResult,
}) async {
_iapOnResult = onResult;
print(
'[IAP] 准备发起购买: id="${productId.trim()}" iapAvailable=${iapAvailable.value}');
if (!iapAvailable.value) {
onResult?.call(false, '内购不可用');
return false;
}
final product = await _queryIapProduct(productId);
if (product == null) {
onResult?.call(false, '未找到内购商品: $productId');
return false;
}
try {
// 记录最近一次用于购买的商品详情,便于后续构建查询参数
_lastIapProduct = product;
final isAndroid =
!kIsWeb && defaultTargetPlatform == TargetPlatform.android;
bool ok;
if (isAndroid && product is GooglePlayProductDetails) {
// 通过环境变量决定订阅或一次性商品路径,避免访问不兼容的属性
final isSubscription =
_getEnvInt('APP_IAP_GOOGLE_IS_SUBSCRIPTION', defaultValue: 0) == 1;
if (isSubscription) {
print('[IAP-android] 订阅商品(ENV),使用 buyNonConsumable');
final gpParam = GooglePlayPurchaseParam(productDetails: product);
print(
'[IAP-android] 调用 buyNonConsumable 参数: productId=${product.id}');
ok = await _inAppPurchase.buyNonConsumable(purchaseParam: gpParam);
print('[IAP-android] buyNonConsumable 返回: $ok');
} else {
// 普通一次性/消耗型商品,使用 buyConsumable
final purchaseParam = PurchaseParam(productDetails: product);
print(
'[IAP-android] 调用 buyConsumable 参数: productId=${product.id} autoConsume=true');
ok = await _inAppPurchase.buyConsumable(
purchaseParam: purchaseParam,
autoConsume: true,
);
print('[IAP-android] buyConsumable 返回: $ok');
}
} else {
// iOS 或非订阅商品,按消耗型处理(如需支持 iOS 订阅,可通过 ENV 切换调用 buyNonConsumable)
final purchaseParam = PurchaseParam(productDetails: product);
print(
'[IAP-ios] 调用 buyConsumable 参数: productId=${product.id} autoConsume=true');
ok = await _inAppPurchase.buyConsumable(
purchaseParam: purchaseParam,
autoConsume: true,
);
print('[IAP-ios] buyConsumable 返回: $ok');
}
if (!ok) {
onResult?.call(false, '无法发起内购');
print('[IAP] 发起内购失败:平台=${_platformString()} productId=${product.id}');
} else {
onResult?.call(true, '已发起内购,请完成支付');
print('[IAP] 已发起内购:等待购买流回调(可能受旧交易阻塞或商店限制)');
}
return ok;
} catch (e) {
if (e is PlatformException &&
(e.code.contains('purchase_cancelled') ||
e.code.contains('storekit2_purchase_cancelled'))) {
onResult?.call(false, '已取消支付');
print(
'[IAP] 用户取消支付(同步抛出) code=${e.code} message=${e.message} product=${product.id}');
return false;
}
onResult?.call(false, '发起内购失败: $e');
print('[IAP] 发起内购异常: $e');
return false;
}
}
Future<void> _handlePurchaseUpdates(List<PurchaseDetails> detailsList) async {
for (final details in detailsList) {
// 记录最近一次 IAP 购买详情
_lastIapPurchase = details;
print(
'[IAP] 更新: status=${details.status} product=${details.productID} purchaseID=${details.purchaseID} error=${details.error}');
switch (details.status) {
case PurchaseStatus.pending:
_iapOnResult?.call(true, '支付处理中…');
break;
case PurchaseStatus.error:
print(
'[IAP] 错误: code=${details.error?.code} message=${details.error?.message}');
_iapOnResult?.call(false, details.error?.message ?? '支付错误');
break;
case PurchaseStatus.purchased:
final txId = details.purchaseID ?? '';
final ok = await _verifyIapWithServer(details);
if (!ok) {
print(
'[IAP] 验证失败 purchased txId=${details.purchaseID} product=${details.productID}');
_iapOnResult?.call(false, details.error?.message ?? '支付错误');
}
if (ok) {
try {
await _inAppPurchase.completePurchase(details);
print('[IAP] 完成交易 purchased txId=${details.purchaseID}');
_iapOnResult?.call(true, details.error?.message ?? '支付成功');
} catch (e, st) {
print('[IAP] 完成交易异常 purchased txId=${details.purchaseID} err=$e');
print('[IAP] 完成交易异常堆栈 purchased $st');
}
}
break;
case PurchaseStatus.restored:
final txId = details.purchaseID ?? '';
final ok = await _verifyIapWithServer(details);
if (!ok) {
print(
'[IAP] 验证失败 restored(silent) txId=${details.purchaseID} product=${details.productID}');
_iapOnResult?.call(false, details.error?.message ?? '支付错误');
}
if (ok) {
try {
await _inAppPurchase.completePurchase(details);
_iapOnResult?.call(true, details.error?.message ?? '支付成功');
print('[IAP] 完成交易 restored(silent) txId=${details.purchaseID}');
} catch (e, st) {
print(
'[IAP] 完成交易异常 restored(silent) txId=${details.purchaseID} err=$e');
print('[IAP] 完成交易异常堆栈 restored(silent) $st');
}
}
break;
case PurchaseStatus.canceled:
_iapOnResult?.call(false, '已取消支付');
print('[IAP] 用户取消支付 product=${details.productID}');
break;
}
}
}
Future<bool> _verifyIapWithServer(PurchaseDetails details) async {
try {
final params = await buildIapAskParams();
final resp = await Api.payverifyorder(params);
Map<String, dynamic>? user;
Map<String, dynamic>? order;
if (resp is Map) {
if (resp['user'] is Map<String, dynamic>) {
user = resp['user'] as Map<String, dynamic>;
} else if (resp['data'] is Map &&
(resp['data']['user'] is Map<String, dynamic>)) {
user = resp['data']['user'] as Map<String, dynamic>;
}
if (resp['order'] is Map<String, dynamic>) {
order = resp['order'] as Map<String, dynamic>;
} else if (resp['data'] is Map &&
(resp['data']['order'] is Map<String, dynamic>)) {
order = resp['data']['order'] as Map<String, dynamic>;
}
}
final int? status = order != null
? (order['status'] is int
? order['status'] as int
: int.tryParse('${order['status']}'))
: null;
final bool ok = status == 1 || user != null;
if (ok && user != null) {
User.instance.updateUserInfo(user);
setVipExptime(User.instance.vipexptime);
}
if (!ok) {
final code = (resp is Map) ? resp['code'] : null;
final msg = (resp is Map) ? (resp['message'] ?? resp['msg']) : null;
print(
'[IAP] 验证失败详情 status=$status code=$code msg=$msg order_id=${params['order_id']}');
}
return ok;
} catch (e) {
print('[IAP] 服务器验证异常: $e');
return false;
}
}
/// 构建 Apple/Google 主动查询(pay_askorder)所需的验证参数
/// 返回与后端 PayAskOrCancelReq 对应的 Map(不再携带 apple_sandbox)
Future<Map<String, dynamic>> buildIapAskParams() async {
final params = <String, dynamic>{};
if (_lastOrderId != null && _lastOrderId!.isNotEmpty) {
params['order_id'] = _lastOrderId;
}
final platform = _platformString();
if (platform == 'ios') {
final receiptOrData =
_lastIapPurchase?.verificationData.serverVerificationData ?? '';
final txId = _lastIapPurchase?.purchaseID ?? '';
// 是否按交易ID校验,默认 false,可通过环境变量开启
final useTxIdEnv = _getEnvBool('APP_IAP_USE_TXID', defaultValue: false);
params['apple_receipt_data'] = useTxIdEnv ? txId : receiptOrData;
params['apple_use_transaction_id'] = useTxIdEnv;
} else if (platform == 'android') {
final packageInfo = await PackageInfo.fromPlatform();
final pkg = packageInfo.packageName;
final token =
_lastIapPurchase?.verificationData.serverVerificationData ?? '';
final productId =
_lastIapPurchase?.productID ?? _lastIapProduct?.id ?? '';
// 订阅标识,默认 false;如需严格区分,可在商品元数据或环境变量中配置
final isSub =
_getEnvBool('APP_IAP_GOOGLE_IS_SUBSCRIPTION', defaultValue: false);
params['google_package_name'] = pkg;
params['google_product_id'] = productId;
params['google_purchase_token'] = token;
params['google_is_subscription'] = isSub;
}
return params;
}
bool _getEnvBool(String key, {required bool defaultValue}) {
try {
final v = dotenv.env[key];
if (v != null && v.isNotEmpty) {
final low = v.toLowerCase();
return low == 'true' || low == '1' || low == 'yes';
}
} catch (_) {}
return defaultValue;
}
int _getEnvInt(String key, {required int defaultValue}) {
try {
final v = dotenv.env[key];
if (v != null && v.isNotEmpty) {
return int.tryParse(v.trim()) ?? defaultValue;
}
} catch (_) {}
return defaultValue;
}
String _platformString() {
if (kIsWeb) return 'web';
switch (defaultTargetPlatform) {
case TargetPlatform.iOS:
return 'ios';
case TargetPlatform.android:
return 'android';
case TargetPlatform.macOS:
return 'macos';
case TargetPlatform.windows:
return 'windows';
case TargetPlatform.linux:
return 'linux';
case TargetPlatform.fuchsia:
return 'fuchsia';
}
}
/// 解析 Apple 的真实商品ID(支持环境前缀/后缀或显式映射)
/// 优先级:显式映射(APP_IOS_IAP_ID_MAP JSON) > 前缀(APP_IOS_IAP_PREFIX) > 后缀(APP_IOS_IAP_SUFFIX) > 原始ID
/// 示例:
/// - APP_IOS_IAP_PREFIX=com.voitrans.
/// - APP_IOS_IAP_ID_MAP={"ai_001":"com.voitrans.ai001","ai_002":"com.voitrans.ai002"}
String resolveAppleProductId(String backendId) {
final raw = backendId.trim();
Map<String, dynamic>? mapped;
try {
final jsonStr = dotenv.env['APP_IOS_IAP_ID_MAP'];
if (jsonStr != null && jsonStr.isNotEmpty) {
mapped = json.decode(jsonStr) as Map<String, dynamic>;
}
} catch (e) {
print('[IAP-ios] 解析 APP_IOS_IAP_ID_MAP 失败: $e');
}
if (mapped != null) {
final m = mapped[raw];
if (m is String && m.trim().isNotEmpty) {
final resolved = m.trim();
print('[IAP-ios] 使用映射ID: $raw -> $resolved');
return resolved;
}
}
final prefix = dotenv.env['APP_IOS_IAP_PREFIX'] ?? '';
final suffix = dotenv.env['APP_IOS_IAP_SUFFIX'] ?? '';
final resolved = '${prefix}${raw}${suffix}';
if (resolved != raw) {
print('[IAP-ios] 使用前后缀ID: $raw -> $resolved');
} else {
print('[IAP-ios] 未配置映射/前缀,使用原始ID: $raw');
}
return resolved;
}
/// 发起 Apple 内购
Future<bool> processApplePayment({
required String productId,
PaymentResultCallback? onResult,
}) async {
if (kIsWeb || defaultTargetPlatform != TargetPlatform.iOS) {
onResult?.call(false, '当前平台不支持 Apple 内购');
return false;
}
if (!iapAvailable.value) {
await _initIAP();
if (!iapAvailable.value) {
onResult?.call(false, '内购不可用');
return false;
}
}
// 解析为 App Store 的真实商品ID
final iosId = resolveAppleProductId(productId);
print('[IAP-ios] 准备使用商品ID购买: backend="$productId" -> store="$iosId"');
return _processIapPayment(productId: iosId, onResult: onResult);
}
/// 发起 Google Play 内购
Future<bool> processGooglePayment({
required String productId,
PaymentResultCallback? onResult,
}) async {
if (kIsWeb || defaultTargetPlatform != TargetPlatform.android) {
onResult?.call(false, '当前平台不支持 Google 内购');
return false;
}
if (!iapAvailable.value) {
await _initIAP();
if (!iapAvailable.value) {
onResult?.call(false, '内购不可用');
return false;
}
}
return _processIapPayment(productId: productId, onResult: onResult);
}
/// 查询支付结果
///
/// [orderId] 订单ID
@ -142,7 +602,7 @@ class PayService extends GetxService {
'product_name': productName,
'product_desc': productDesc ?? '',
'amount': amount,
'payment_method': paymentMethod,
'payment_method': 4,
'client_ip': clientIp ?? '',
'notify_url': notifyUrl ?? '',
'extra_data': extraData ?? '',
@ -150,9 +610,36 @@ class PayService extends GetxService {
print('创建支付订单: $response');
// 检查响应是否成功
if (response != null) {
// 尝试提取订单号,兼容多种返回字段
String? orderId;
final candidates = [
'order_id',
'orderId',
'out_trade_no',
'outTradeNo',
];
for (final key in candidates) {
final v = response[key];
if (v is String && v.isNotEmpty) {
orderId = v;
break;
}
}
if (orderId == null && response['data'] is Map<String, dynamic>) {
final data = response['data'] as Map<String, dynamic>;
for (final key in candidates) {
final v = data[key];
if (v is String && v.isNotEmpty) {
orderId = v;
break;
}
}
}
_lastOrderId = orderId;
final pay_params = response["pay_params"] as Map<String, dynamic>;
// 返回微信支付所需的参数
return {
final result = {
'appId': pay_params['appid'],
'partnerId': pay_params['partnerid'],
'prepayId': pay_params['prepayid'],
@ -161,6 +648,10 @@ class PayService extends GetxService {
'timestamp': pay_params['timestamp'],
'sign': pay_params['sign'],
};
if (orderId != null) {
result['orderId'] = orderId;
}
return result;
} else {
print('创建支付订单失败: ${response?['message'] ?? '未知错误'}');
return null;
@ -231,7 +722,6 @@ class PayService extends GetxService {
productName: description,
productDesc: description,
amount: amount,
paymentMethod: 3, // 支付宝支付
notifyUrl: 'https://api.ideapsound.com/api/home/pay_alipaynotify',
);
@ -326,7 +816,6 @@ class PayService extends GetxService {
required String productName,
String? productDesc,
required int amount,
int paymentMethod = 2, // 2表示支付宝
String? clientIp,
String? notifyUrl,
String? extraData,
@ -338,7 +827,7 @@ class PayService extends GetxService {
'product_name': productName,
'product_desc': productDesc ?? '',
'amount': amount,
'payment_method': paymentMethod,
'payment_method': 3,
'client_ip': clientIp ?? '',
'notify_url': notifyUrl ?? '',
'extra_data': extraData ?? '',
@ -348,6 +837,32 @@ class PayService extends GetxService {
// 检查响应是否成功
if (response != null && response['alipay_pay_params'] != null) {
// 解析订单号并缓存
String? orderId;
final candidates = [
'order_id',
'orderId',
'out_trade_no',
'outTradeNo',
];
for (final key in candidates) {
final v = response[key];
if (v is String && v.isNotEmpty) {
orderId = v;
break;
}
}
if (orderId == null && response['data'] is Map<String, dynamic>) {
final data = response['data'] as Map<String, dynamic>;
for (final key in candidates) {
final v = data[key];
if (v is String && v.isNotEmpty) {
orderId = v;
break;
}
}
}
_lastOrderId = orderId;
// 返回支付宝订单信息字符串
return response['alipay_pay_params'] as String?;
} else {
@ -359,4 +874,298 @@ class PayService extends GetxService {
return null;
}
}
/// 创建 PayPal 支付订单
/// 返回需要打开的支付授权链接(approval_url)或支付页面URL
Future<String?> createPaypalOrder({
required String productId,
required String productName,
String? productDesc,
required int amount,
String? clientIp,
String? notifyUrl,
String? extraData,
}) async {
try {
// 回跳地址:自定义 Scheme,分别用于支付完成与取消
const returnUrl = 'deepvoiceclient://paypal/return';
const cancelUrl = 'deepvoiceclient://paypal/cancel';
final response = await Api.paycreateorder({
'product_id': productId,
'product_name': productName,
'product_desc': productDesc ?? '',
'amount': amount,
'payment_method': 5,
'client_ip': clientIp ?? '',
'notify_url': notifyUrl ?? '',
'extra_data': extraData ?? '',
// 供后端设置 PayPal application_context 用于网页授权回跳
'return_url': returnUrl,
'cancel_url': cancelUrl,
});
if (response != null) {
print('创建 PayPal 订单响应: $response');
// 1) 提取并缓存平台订单号(用于回查)
String? appOrderId;
const candidates = [
'order_id',
'orderId',
'out_trade_no',
'outTradeNo',
];
for (final key in candidates) {
final v = response[key];
if (v is String && v.isNotEmpty) {
appOrderId = v;
break;
}
}
final data = response['data'];
if (appOrderId == null && data is Map<String, dynamic>) {
for (final key in candidates) {
final v = data[key];
if (v is String && v.isNotEmpty) {
appOrderId = v;
break;
}
}
}
_lastOrderId = appOrderId; // 记录APP侧订单号(如 APP2025...),用于 pay_askorder
// 2) 优先解析 paypal_pay_params 字段(后端返回JSON字符串,含 links)
String? rawParams;
final topParams = response['paypal_pay_params'];
final dataParams =
(data is Map<String, dynamic>) ? data['paypal_pay_params'] : null;
if (topParams is String && topParams.isNotEmpty) {
rawParams = topParams;
} else if (dataParams is String && dataParams.isNotEmpty) {
rawParams = dataParams;
}
if (rawParams != null) {
try {
final parsed = jsonDecode(rawParams);
if (parsed is Map<String, dynamic>) {
final links = parsed['links'];
if (links is List) {
for (final item in links) {
if (item is Map) {
final rel = item['rel']?.toString();
final hrefRaw = item['href']?.toString();
if (rel == 'approve' &&
hrefRaw != null &&
hrefRaw.isNotEmpty) {
// 清理日志中可能出现的反引号等噪音字符
final href = hrefRaw.replaceAll('`', '').trim();
print(
'解析到 PayPal 授权链接(links.approve): $href, appOrderId: $appOrderId');
return href;
}
}
}
}
}
} catch (e) {
print('解析 paypal_pay_params 失败: $e');
}
}
// 3) 回退:尝试从常见字段直接取URL
final urlKeys = [
'paypal_pay_url',
'approval_url',
'paypalApprovalUrl',
'pay_url',
'payment_url',
'url',
];
for (final key in urlKeys) {
final url = response[key];
if (url is String && url.isNotEmpty) {
print('解析到 PayPal 授权链接($key): $url, appOrderId: $appOrderId');
return url;
}
}
if (data is Map<String, dynamic>) {
for (final key in urlKeys) {
final url = data[key];
if (url is String && url.isNotEmpty) {
print(
'解析到 PayPal 授权链接(data.$key): $url, appOrderId: $appOrderId');
return url;
}
}
}
}
print('创建 PayPal 订单失败或未返回有效URL: $response');
return null;
} catch (e) {
print('创建 PayPal 订单异常: $e');
return null;
}
}
/// 拉起 PayPal 支付(打开授权链接)。
/// 注意:该方法仅负责跳转至 PayPal 页面,结果需要后端回调通知。
Future<bool> paypalPay({
required String approvalUrl,
PaymentResultCallback? onResult,
}) async {
try {
print('准备打开 PayPal 授权页面: $approvalUrl');
final uri = Uri.parse(approvalUrl);
final ok = await launchUrl(uri, mode: LaunchMode.externalApplication);
if (ok) {
onResult?.call(true, '已打开 PayPal,请完成支付');
} else {
onResult?.call(false, '无法打开 PayPal 支付页面');
}
return ok;
} catch (e) {
onResult?.call(false, '打开 PayPal 异常: $e');
return false;
}
}
/// 一体化的 PayPal 支付流程:创建订单 -> 打开授权链接
Future<bool> processPaypalPayment({
required String productId,
required int amount,
required String description,
PaymentResultCallback? onResult,
}) async {
try {
final approvalUrl = await createPaypalOrder(
productId: productId,
productName: description,
productDesc: description,
amount: amount,
notifyUrl: 'https://api.ideapsound.com/api/home/pay_paypalnotify',
);
if (approvalUrl == null) {
onResult?.call(false, '创建 PayPal 订单失败');
return false;
}
return await paypalPay(approvalUrl: approvalUrl, onResult: onResult);
} catch (e) {
onResult?.call(false, 'PayPal 支付流程异常: $e');
return false;
}
}
/// 创建 Apple 内购订单,仅用于在服务端生成并记录订单号,后续回查使用
/// 返回服务端生成的 `order_id`,若失败则返回 null
Future<String?> createAppleIapOrder({
required String productId,
required String productName,
String? productDesc,
required int amount,
}) async {
try {
final resp = await Api.paycreateorder({
'product_id': productId,
'product_name': productName,
'product_desc': productDesc ?? '',
'amount': amount,
'payment_method': 6,
});
if (resp != null) {
String? orderId;
const candidates = [
'order_id',
'orderId',
'out_trade_no',
'outTradeNo'
];
for (final k in candidates) {
final v = resp[k];
if (v is String && v.isNotEmpty) {
orderId = v;
break;
}
}
if (orderId == null && resp['data'] is Map<String, dynamic>) {
final data = resp['data'] as Map<String, dynamic>;
for (final k in candidates) {
final v = data[k];
if (v is String && v.isNotEmpty) {
orderId = v;
break;
}
}
}
_lastOrderId = orderId;
return orderId;
}
return null;
} catch (e) {
print('创建 Apple IAP 订单异常: $e');
return null;
}
}
/// 创建 Google 内购订单,仅用于在服务端生成并记录订单号,后续回查使用
/// 返回服务端生成的 `order_id`,若失败则返回 null
Future<String?> createGoogleIapOrder({
required String productId,
required String productName,
String? productDesc,
required int amount,
}) async {
try {
final resp = await Api.paycreateorder({
'product_id': productId,
'product_name': productName,
'product_desc': productDesc ?? '',
'amount': amount,
'payment_method': 7,
});
if (resp != null) {
String? orderId;
const candidates = [
'order_id',
'orderId',
'out_trade_no',
'outTradeNo'
];
for (final k in candidates) {
final v = resp[k];
if (v is String && v.isNotEmpty) {
orderId = v;
break;
}
}
if (orderId == null && resp['data'] is Map<String, dynamic>) {
final data = resp['data'] as Map<String, dynamic>;
for (final k in candidates) {
final v = data[k];
if (v is String && v.isNotEmpty) {
orderId = v;
break;
}
}
}
_lastOrderId = orderId;
return orderId;
}
return null;
} catch (e) {
print('创建 Google IAP 订单异常: $e');
return null;
}
}
/// 请求蓝牙权限
void setVipExptime(int vipexptime) {
try {
AgentService.setVipExptime(vipexptime);
} catch (e) {
print('请求蓝牙权限失败: ${e.toString()}');
}
}
}

6
lib/data/services/speech_impl/azure_asr_service.dart

@ -191,7 +191,10 @@ class AzureAsrService extends GetxService implements AsrService {
/// - 在 600ms 的冷却时间内再次调用会被防抖拦截并返回 false;
/// - 首次或冷却期外调用会继续启动连续识别;
/// - 若当前已处于连续识别中,会先调用停止后再启动。
Future<bool> startContinuousRecognition(bool audioSourceType) async {
Future<bool> startContinuousRecognition(
bool audioSourceType, {
bool isRemoveFirstPunctuation = true,
}) async {
// 防抖判断:短时间内重复调用直接拦截
final now = DateTime.now();
if (_lastStartAt != null && now.difference(_lastStartAt!) < _debounce) {
@ -212,6 +215,7 @@ class AzureAsrService extends GetxService implements AsrService {
final bool result =
await _channel.invokeMethod('startContinuousRecognition', {
'audioSourceType': audioSourceType,
'isRemoveFirstPunctuation': isRemoveFirstPunctuation,
});
if (!result) {

8
lib/data/services/speech_impl/azure_tts_service.dart

@ -182,6 +182,14 @@ class AzureTtsService extends GetxService implements TtsService {
}
}
@override
Future<bool> setVoiceFlocking(String speakerProfileId) async {
final result = await _channel.invokeMethod('setVoiceFlocking', {
'speakerProfileId': speakerProfileId,
});
return result;
}
@override
Future<bool> startspeak(String sessionid) async {
if (!_isInitialized) await initialize();

5
lib/data/services/speech_impl/voice_clone_tts_service.dart

@ -94,6 +94,11 @@ class VoiceCloneTtsService extends GetxService implements TtsService {
}
}
@override
Future<bool> setVoiceFlocking(String speakerProfileId) async {
return true;
}
// 语音合成
Future<void> _speechSynthesis(String text) async {
await _tryConnecting();

5
lib/data/services/speech_impl/volcano_asr_api_service.dart

@ -862,7 +862,10 @@ class VolcanoAsrApiService implements AsrService {
}
@override
Future<bool> startContinuousRecognition(bool audioSourceType) {
Future<bool> startContinuousRecognition(
bool audioSourceType, {
bool isRemoveFirstPunctuation = true,
}) {
// TODO: implement startContinuousRecognition
throw UnimplementedError();
}

5
lib/data/services/speech_impl/volcano_asr_service.dart

@ -397,7 +397,10 @@ class VolcanoAsrService extends GetxService implements AsrService {
}
@override
Future<bool> startContinuousRecognition(bool audioSourceType) {
Future<bool> startContinuousRecognition(
bool audioSourceType, {
bool isRemoveFirstPunctuation = true,
}) {
// TODO: implement startContinuousRecognition
throw UnimplementedError();
}

5
lib/data/services/speech_impl/volcano_tts_service.dart

@ -185,6 +185,11 @@ class VolcanoTtsService extends GetxService implements TtsService {
}
}
@override
Future<bool> setVoiceFlocking(String speakerProfileId) async {
return true;
}
/// 设置是否启用音频数据回调
Future<bool> setEnableAudioCallback(bool enable) async {
if (!await _ensureInitialized()) return false;

5
lib/data/services/speech_impl/xunfei_asr_service.dart

@ -321,7 +321,10 @@ class XunfeiAsrService extends GetxService implements AsrService {
}
@override
Future<bool> startContinuousRecognition(bool audioSourceType) {
Future<bool> startContinuousRecognition(
bool audioSourceType, {
bool isRemoveFirstPunctuation = true,
}) {
// TODO: implement startContinuousRecognition
throw UnimplementedError();
}

3
lib/data/services/tts_service.dart

@ -19,6 +19,9 @@ abstract class TtsService {
/// 设置语音
Future<bool> setVoice(String voiceName);
/// 设置语音复刻
Future<bool> setVoiceFlocking(String speakerProfileId);
///开始新的播放会话
Future<bool> startspeak(String sessionid);

783
lib/data/services/usage_stats_service.dart

@ -0,0 +1,783 @@
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import '../models/translation_usage_stats.dart';
import '../models/meeting_usage_stats.dart';
import '../../core/utils/logger.dart';
import 'network/api.dart';
import '../models/goods.dart';
import '../models/user_Info.dart';
/// 使用量统计服务
///
class UsageStatsService extends GetxService {
static const String _dailyStatsKey = 'daily_translation_stats';
static const String _meetingDailyKey = 'daily_meeting_asr_stats';
static const String _meetingOsDailykey = 'daily_meeting_os_stats';
final GetStorage _storage = GetStorage();
// 实时统计数据
final Rx<RealtimeUsageStats> realtimeTranslationStats =
RealtimeUsageStats().obs;
// 当日统计数据
final Rx<TranslationUsageStats> todayTranslationStats =
TranslationUsageStats.empty('').obs;
@override
void onInit() {
super.onInit();
_initializeService();
}
/// 初始化服务
void _initializeService() {
_loadTodayTranslationStats();
Logger.info('lxm--使用量统计服务初始化完成');
}
/// 加载当日翻译统计数据
void _loadTodayTranslationStats() {
try {
final today = DateTime.now();
final todayKey =
'${today.year}-${today.month.toString().padLeft(2, '0')}-${today.day.toString().padLeft(2, '0')}';
final statsData = _storage.read('${_dailyStatsKey}_$todayKey');
if (statsData != null) {
todayTranslationStats.value = TranslationUsageStats.fromJson(
Map<String, dynamic>.from(statsData));
} else {
todayTranslationStats.value =
TranslationUsageStats.empty(getCurrentUserId());
}
} catch (e) {
Logger.error('加载当日翻译统计数据失败: $e');
todayTranslationStats.value =
TranslationUsageStats.empty(getCurrentUserId());
}
}
/// 获取当前用户ID
String getCurrentUserId() {
try {
final userInfo = _storage.read('user_info');
if (userInfo != null && userInfo['user'] != null) {
return userInfo['user']['uid'] ?? 'anonymous';
}
} catch (e) {
Logger.warning('获取用户ID失败: $e');
}
return 'anonymous';
}
MeetingAsrDailyStats _loadMeetingDaily(String dateKey) {
final data = _storage.read('${_meetingDailyKey}_$dateKey');
if (data != null) {
return MeetingAsrDailyStats.fromJson(Map<String, dynamic>.from(data));
}
return MeetingAsrDailyStats(
date: dateKey, userId: getCurrentUserId(), items: []);
}
void _saveMeetingDaily(MeetingAsrDailyStats stats) {
_storage.write('${_meetingDailyKey}_${stats.date}', stats.toJson());
Logger.d('MeetingASRrecord',
'保存会议当日统计: date=${stats.date}, items=${stats.items.length}');
}
String _formatDate(DateTime d) {
final y = d.year;
final m = d.month.toString().padLeft(2, '0');
final day = d.day.toString().padLeft(2, '0');
return '$y-$m-$day';
}
/// 记录单次对象存储上传
/// [meetingId] 会议ID
/// [storageUrl] 云端存储URL
/// [storageBytes] 文件大小(字节)
/// [transferBytes] 数据传输字节数
/// [uploadTimestamp] 上传完成时间戳(毫秒)
void recordMeetingObjectStorage({
required int meetingId,
required String storageUrl,
required int storageBytes,
required int transferBytes,
required int uploadTimestamp,
}) {
final dateKey =
_formatDate(DateTime.fromMillisecondsSinceEpoch(uploadTimestamp));
final storageKey = '${_meetingOsDailykey}_$dateKey';
final raw = _storage.read(storageKey);
List<MeetingObjectStorageRecord> uploads = [];
if (raw is List) {
uploads = raw
.map((e) =>
MeetingObjectStorageRecord.fromJson(Map<String, dynamic>.from(e)))
.toList();
}
// final id = 'os_${uploadTimestamp}_${meetingId}';
final record = MeetingObjectStorageRecord(
meetingId: meetingId,
storageUrl: storageUrl,
storageBytes: storageBytes,
transferBytes: transferBytes,
uploadTimestamp: uploadTimestamp,
);
// 使用 meetingId + storageUrl 作为唯一标识来判断重复
final exists = uploads.indexWhere(
(e) => e.meetingId == meetingId && e.storageUrl == storageUrl) >=
0;
if (!exists) {
uploads.add(record);
_storage.write(storageKey, uploads.map((e) => e.toJson()).toList());
Logger.d('MeetingOSrecord',
'新增对象存储上传: meetingId=$meetingId, size=$storageBytes, transfer=$transferBytes');
} else {
Logger.d('MeetingOSrecord',
'重复对象存储上传忽略: meetingId=$meetingId, url=$storageUrl');
}
}
/// 添加或更新会议ASR记录
/// [record] 会议ASR记录
/// 该方法用于记录一次会议语音识别(ASR)的提交记录。它会根据记录的时间戳确定日期,
/// 并将记录添加到该日期的会议ASR记录列表中。如果记录已存在,则会更新该记录。
void addMeetingAsrRecord(MeetingAsrRecord record) {
final dateKey = _formatDate(
DateTime.fromMillisecondsSinceEpoch(record.submitTimestamp));
final daily = _loadMeetingDaily(dateKey);
final idx = daily.items.indexWhere((e) => e.id == record.id);
if (idx >= 0) {
daily.items[idx] = record;
Logger.d('MeetingASRrecord',
'更新会议ASR记录: id=${record.id}, meetingId=${record.meetingId}, date=${dateKey}');
} else {
daily.items.add(record);
Logger.d('MeetingASRrecord',
'新增会议ASR记录: id=${record.id}, meetingId=${record.meetingId}, date=${dateKey}');
}
_saveMeetingDaily(daily);
Logger.i('MeetingASRrecord',
'会议ASR提交: id=${record.id}, meetingId=${record.meetingId}, audioSeconds=${record.audioSeconds}, fileSizeBytes=${record.fileSizeBytes}, language=${record.language}, date=${dateKey}');
}
/// 完成会议ASR记录
/// [id] 会议ASR记录ID
/// [transcriptBytes] 转写结果文本字节数
/// [completeTimestamp] 完成时间戳
/// 该方法用于标记一次会议语音识别(ASR)任务为已完成状态。
/// 它会根据记录ID在最近3天的会议ASR记录列表中查找匹配项,
/// 如果找到,则更新该记录的状态为已完成,并记录转写结果文本字节数和完成时间戳。
void completeMeetingAsrRecord({
required String id,
required int transcriptBytes,
required int completeTimestamp,
}) {
final now = DateTime.now();
for (int i = 0; i < 3; i++) {
final dateKey = _formatDate(now.subtract(Duration(days: i)));
final daily = _loadMeetingDaily(dateKey);
final idx = daily.items.indexWhere((e) => e.id == id);
if (idx >= 0) {
final old = daily.items[idx];
daily.items[idx] = MeetingAsrRecord(
id: old.id,
meetingId: old.meetingId,
taskId: old.taskId,
audioSeconds: old.audioSeconds,
fileSizeBytes: old.fileSizeBytes,
language: old.language,
submitTimestamp: old.submitTimestamp,
status: asrStatusCompleted,
transcriptBytes: transcriptBytes,
completeTimestamp: completeTimestamp,
);
_saveMeetingDaily(daily);
Logger.i('MeetingASRrecord',
'会议ASR完成: id=${id}, meetingId=${old.meetingId}, transcriptBytes=${transcriptBytes}, audioSeconds=${old.audioSeconds}, date=${dateKey}');
try {
_reportMeetingUsageToServer(
audioSeconds: old.audioSeconds,
audioBytes: old.fileSizeBytes,
language: old.language,
transcriptBytes: transcriptBytes,
);
} catch (e) {
Logger.error('会议用量上报(完成)失败: $e');
}
return;
}
}
}
/// 上报会议用量到服务器
/// [audioSeconds] 音频时长(秒)
/// [audioBytes] 音频文件大小(字节)
/// [language] 识别语言
/// [transcriptBytes] 转写结果文本字节数(可选)
/// 该方法用于将会议语音识别(ASR)的用量数据上报到服务器。
/// 它会根据提供的参数构建一个包含会议用量类型、音频时长、音频文件大小、
/// 识别语言以及可选的转写结果文本字节数的参数对象。
/// 然后,它会调用API接口将该参数对象发送到服务器进行处理。
/// 如果上报成功,服务器会返回一个响应,该方法会根据响应更新本地的用户积分(非总积分)。
Future<void> _reportMeetingUsageToServer({
required int audioSeconds,
required int audioBytes,
required String language,
int? transcriptBytes,
}) async {
try {
final params = {
'usagetype': UsageType.Meet.toInt,
'usages': {
'MEETING_ASR_AUDIO_SECONDS': audioSeconds,
// 'MEETING_ASR_AUDIO_BYTES': audioBytes,
// if (transcriptBytes != null)
// 'MEETING_ASR_TRANSCRIPT_BYTES': transcriptBytes,
// 'MEETING_ASR_LANGUAGE_$language': 1,
},
};
Logger.info('lxm---MEET用量上报参数: $params');
final response = await Api.usagesResPoints(params);
Logger.info('lxm---MEET用量上报响应: $response');
_applyUsageResponse(response);
} catch (e) {
Logger.error('会议用量上报失败: $e');
}
}
/// 记录翻译API调用
void recordTranslationApiCall({
required String sourceText,
required String targetText,
required String sourceLanguage,
required String targetLanguage,
required String mode,
}) {
try {
// 更新实时统计
realtimeTranslationStats.value.translationCount++;
realtimeTranslationStats.value.sourceTextCharacters += sourceText.length;
realtimeTranslationStats.value.ttsTextCharacters += targetText.length;
realtimeTranslationStats.value.currentLanguagePair =
'$sourceLanguage-$targetLanguage';
realtimeTranslationStats.value.currentMode = mode;
realtimeTranslationStats.refresh();
// 更新当日统计 - 使用多维度统计
final languagePair = '$sourceLanguage→$targetLanguage';
// 更新语言对统计
final newLanguagePairStats = Map<String, LanguagePairStats>.from(
todayTranslationStats.value.languagePairStats);
if (newLanguagePairStats.containsKey(languagePair)) {
final existing = newLanguagePairStats[languagePair]!;
newLanguagePairStats[languagePair] = LanguagePairStats(
languagePair: languagePair,
translationCount: existing.translationCount + 1,
sourceCharacters: existing.sourceCharacters + sourceText.length,
);
} else {
newLanguagePairStats[languagePair] = LanguagePairStats(
languagePair: languagePair,
translationCount: 1,
sourceCharacters: sourceText.length,
);
}
// 更新模式统计
final newModeStats = Map<String, TranslationModeStats>.from(
todayTranslationStats.value.modeStats);
if (newModeStats.containsKey(mode)) {
final existing = newModeStats[mode]!;
newModeStats[mode] = existing.copyWith(
apiCalls: existing.apiCalls + 1,
sourceCharacters: existing.sourceCharacters + sourceText.length,
ttsCharacters: existing.ttsCharacters + targetText.length,
);
} else {
newModeStats[mode] = TranslationModeStats(
apiCalls: 1,
sourceCharacters: sourceText.length,
ttsCharacters: targetText.length,
);
}
todayTranslationStats.value = todayTranslationStats.value.copyWith(
translationApiCalls:
todayTranslationStats.value.translationApiCalls + 1,
sourceTextCharacters: todayTranslationStats.value.sourceTextCharacters +
sourceText.length,
ttsTextCharacters:
todayTranslationStats.value.ttsTextCharacters + targetText.length,
languagePairStats: newLanguagePairStats,
modeStats: newModeStats,
);
_saveTodayStats();
Logger.info(
'记录翻译API调用: 源文本${sourceText.length}字符, 目标文本${targetText.length}字符');
} catch (e) {
Logger.error('记录翻译API调用失败: $e');
}
}
/// 记录ASR API调用 - 优化版(精确统计参数)
void recordAsrApiCall({
required int effectiveDurationSeconds, // 有效语音时长(VAD检测的实际语音)
required int totalDurationSeconds, // 总会话时长(包含静音)
required String language,
required String mode, // 翻译模式
String? audioFormat, // 音频格式(可选)
int? sampleRate, // 采样率(可选)
}) {
try {
// 更新实时统计(使用有效语音时长作为主要计费依据)
realtimeTranslationStats.value.effectiveAudioDuration +=
effectiveDurationSeconds;
realtimeTranslationStats.value.totalSessionDuration +=
totalDurationSeconds;
realtimeTranslationStats.refresh();
// 更新模式统计
final newModeStats = Map<String, TranslationModeStats>.from(
todayTranslationStats.value.modeStats);
if (newModeStats.containsKey(mode)) {
final existing = newModeStats[mode]!;
newModeStats[mode] = existing.copyWith(
effectiveAudioDuration:
existing.effectiveAudioDuration + effectiveDurationSeconds,
);
} else {
newModeStats[mode] = TranslationModeStats(
effectiveAudioDuration: effectiveDurationSeconds,
);
}
// 更新当日统计
todayTranslationStats.value = todayTranslationStats.value.copyWith(
asrApiCalls: todayTranslationStats.value.asrApiCalls + 1,
effectiveAudioDuration:
todayTranslationStats.value.effectiveAudioDuration +
effectiveDurationSeconds,
totalSessionDuration: todayTranslationStats.value.totalSessionDuration +
totalDurationSeconds,
modeStats: newModeStats,
);
_saveTodayStats();
Logger.info(
'ASR统计: 有效语音${effectiveDurationSeconds}秒, 总时长${totalDurationSeconds}秒, 语言$language, 模式$mode');
} catch (e) {
Logger.error('记录ASR API调用失败: $e');
}
_reportAsrUsageToServer(
effectiveDurationSeconds: effectiveDurationSeconds,
//totalDurationSeconds: totalDurationSeconds,
language: language,
mode: mode,
);
}
/// 上报ASR用量到服务器
/// [effectiveDurationSeconds] 有效语音时长(秒)
/// [language] 识别语言
/// [mode] 翻译模式
/// 该方法用于将ASR(语音识别)的用量数据上报到服务器。
/// 它会根据提供的参数构建一个包含用量类型、有效语音时长、识别语言以及翻译模式的参数对象。
/// 然后,它会调用API接口将该参数对象发送到服务器进行处理。
/// 如果上报成功,服务器会返回一个响应,该方法会根据响应更新本地的用户积分(非总积分)。
Future<void> _reportAsrUsageToServer({
required int effectiveDurationSeconds,
//required int totalDurationSeconds,
required String language,
required String mode,
}) async {
try {
final params = {
'usagetype': UsageType.Translation.toInt,
'usages': {
// 'TRANSLATION_ASR_EFFECTIVE_SECONDS': effectiveDurationSeconds,
//'TRANSLATION_ASR_TOTAL_SECONDS': totalDurationSeconds,
'TRANSLATION_MODE_$mode': effectiveDurationSeconds,
'TRANSLATION_ASR_LANGUAGE_$language': 1,
// 'TRANSLATION_SOURCE_CHARACTERS':
// realtimeTranslationStats.value.sourceTextCharacters,
// 'TRANSLATION_TARGET_CHARACTERS':
// realtimeTranslationStats.value.ttsTextCharacters,
},
};
Logger.info('lxm---ASR用量上报参数: $params');
final response = await Api.usagesResPoints(params);
Logger.info('lxm---ASR用量上报响应: $response');
_applyUsageResponse(response);
} catch (e) {
Logger.error('记录ASR API调用失败: $e');
}
}
/// 根据服务器用量上报回应,更新用户积分(非总积分)
/// 用量类型:0 AI聊天、1 翻译、2 会议
void _applyUsageResponse(dynamic response) {
try {
if (response is! Map) return;
final usagesObj = response['usages'];
if (usagesObj is! Map) return;
final usages = Map<String, dynamic>.from(usagesObj as Map);
int _asInt(dynamic v) {
if (v == null) return 0;
if (v is int) return v;
if (v is num) return v.toInt();
if (v is String) return int.tryParse(v) ?? 0;
return 0;
}
final Map<String, dynamic> update = {};
usages.forEach((k, v) {
final key = int.tryParse(k.toString());
final val = _asInt(v);
if (key == null) return;
switch (key) {
case 0:
update['aichatintegral'] = val;
break;
case 1:
update['tradeintegral'] = val;
break;
case 2:
update['meetintegral'] = val;
break;
}
});
if (update.isNotEmpty) {
User.instance.updateUserInfo(update);
Logger.info('积分更新: $update');
}
} catch (e) {
Logger.error('解析用量回应并更新积分失败: $e');
}
}
/// 记录TTS API调用
void recordTtsApiCall({
required String text,
required int durationSeconds,
required String language,
}) {
try {
// 更新实时统计
realtimeTranslationStats.value.totalSessionDuration += durationSeconds;
realtimeTranslationStats.refresh();
// 更新当日统计(TTS按字符数计费,不是按时长)
todayTranslationStats.value = todayTranslationStats.value.copyWith(
ttsApiCalls: todayTranslationStats.value.ttsApiCalls + 1,
ttsTextCharacters:
todayTranslationStats.value.ttsTextCharacters + text.length,
totalSessionDuration:
todayTranslationStats.value.totalSessionDuration + durationSeconds,
);
_saveTodayStats();
Logger.info('记录TTS API调用: 文本${text.length}字符, 时长${durationSeconds}秒');
} catch (e) {
Logger.error('记录TTS API调用失败: $e');
}
}
/// 记录AI摘要API调用
void recordAiSummaryApiCall() {
try {
// 更新当日统计
todayTranslationStats.value = todayTranslationStats.value.copyWith(
aiSummaryApiCalls: todayTranslationStats.value.aiSummaryApiCalls + 1,
);
_saveTodayStats();
Logger.info('记录AI摘要API调用');
} catch (e) {
Logger.error('记录AI摘要API调用失败: $e');
}
}
/// 开始新会话
void startNewSession() {
realtimeTranslationStats.value.reset();
// 更新当日会话数
todayTranslationStats.value = todayTranslationStats.value.copyWith(
sessionCount: todayTranslationStats.value.sessionCount + 1,
);
_saveTodayStats();
Logger.info('开始新的翻译会话');
}
/// 保存当日统计数据
void _saveTodayStats() {
try {
final today = DateTime.now();
final todayKey =
'${today.year}-${today.month.toString().padLeft(2, '0')}-${today.day.toString().padLeft(2, '0')}';
_storage.write(
'${_dailyStatsKey}_$todayKey', todayTranslationStats.value.toJson());
} catch (e) {
Logger.error('保存当日统计数据失败: $e');
}
}
/// 获取历史统计数据
Future<List<TranslationUsageStats>> getHistoryStats({
required DateTime startDate,
required DateTime endDate,
}) async {
try {
final List<TranslationUsageStats> historyStats = [];
for (DateTime date = startDate;
date.isBefore(endDate) || date.isAtSameMomentAs(endDate);
date = date.add(const Duration(days: 1))) {
final dateKey =
'${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}';
final statsData = _storage.read('${_dailyStatsKey}_$dateKey');
if (statsData != null) {
historyStats.add(TranslationUsageStats.fromJson(
Map<String, dynamic>.from(statsData)));
}
}
return historyStats;
} catch (e) {
Logger.error('获取历史统计数据失败: $e');
return [];
}
}
/// 清理过期数据(保留最近90天)
void cleanupOldData() {
try {
final cutoffDate = DateTime.now().subtract(const Duration(days: 90));
final allKeys = _storage.getKeys();
for (final key in allKeys) {
if (key.startsWith(_dailyStatsKey)) {
final dateStr = key.replaceFirst('${_dailyStatsKey}_', '');
try {
final date = DateTime.parse(dateStr);
if (date.isBefore(cutoffDate)) {
_storage.remove(key);
Logger.info('清理过期统计数据: $key');
}
} catch (e) {
// 忽略解析错误的键
}
}
}
} catch (e) {
Logger.error('清理过期数据失败: $e');
}
}
/// 获取月度统计汇总
Future<TranslationUsageStats> getMonthlyStats(int year, int month) async {
try {
final startDate = DateTime(year, month, 1);
final endDate = DateTime(year, month + 1, 0); // 月末
final dailyStats = await getHistoryStats(
startDate: startDate,
endDate: endDate,
);
if (dailyStats.isEmpty) {
return TranslationUsageStats.empty(getCurrentUserId());
}
// 汇总月度数据
int totalTranslationCalls = 0;
int totalAsrCalls = 0;
int totalTtsCalls = 0;
int totalAiSummaryCalls = 0;
int totalSourceChars = 0;
int totalTargetChars = 0;
int totalRecordingDuration = 0;
int totalTtsPlayDuration = 0;
int totalSessions = 0;
//double totalCost = 0.0;
final Map<String, int> combinedLanguagePairUsage = {};
final Map<String, int> combinedModeUsage = {};
for (final stats in dailyStats) {
totalTranslationCalls += stats.translationApiCalls;
totalAsrCalls += stats.asrApiCalls;
totalTtsCalls += stats.ttsApiCalls;
totalAiSummaryCalls += stats.aiSummaryApiCalls;
totalSourceChars += stats.sourceCharacterCount;
totalTargetChars += stats.targetCharacterCount;
totalRecordingDuration += stats.audioRecordingDuration;
totalTtsPlayDuration += stats.ttsPlaybackDuration;
totalSessions += stats.sessionCount;
// totalCost += stats.estimatedCost;
// 合并语言对使用统计
stats.languagePairUsage.forEach((key, value) {
combinedLanguagePairUsage[key] =
(combinedLanguagePairUsage[key] ?? 0) + value;
});
// 合并模式使用统计
stats.modeUsage.forEach((key, value) {
combinedModeUsage[key] = (combinedModeUsage[key] ?? 0) + value;
});
}
return TranslationUsageStats(
id: 'monthly_${year}_$month',
date: startDate,
userId: getCurrentUserId(),
timeGranularity: 'month',
translationApiCalls: totalTranslationCalls,
asrApiCalls: totalAsrCalls,
ttsApiCalls: totalTtsCalls,
aiSummaryApiCalls: totalAiSummaryCalls,
sourceTextCharacters: totalSourceChars,
effectiveAudioDuration: totalRecordingDuration,
ttsTextCharacters: totalTargetChars,
totalSessionDuration: totalTtsPlayDuration,
sessionCount: totalSessions,
// estimatedCost: totalCost,
);
} catch (e) {
Logger.error('获取月度统计失败: $e');
return TranslationUsageStats.empty(getCurrentUserId());
}
}
/// 获取会议历史统计
///
/// 从[startDate]到[endDate]的会议ASR记录。
Future<List<MeetingAsrDailyStats>> getMeetingHistoryStats({
required DateTime startDate,
required DateTime endDate,
}) async {
try {
final List<MeetingAsrDailyStats> list = [];
for (DateTime date = startDate;
date.isBefore(endDate) || date.isAtSameMomentAs(endDate);
date = date.add(const Duration(days: 1))) {
final key = _formatDate(date);
final daily = _loadMeetingDaily(key);
if (daily.items.isNotEmpty) {
list.add(daily);
}
}
Logger.i('MeetingASRrecord',
'获取会议历史统计: start=${_formatDate(startDate)}, end=${_formatDate(endDate)}, 有效天数=${list.length}');
return list;
} catch (e) {
Logger.error('获取会议历史统计失败: $e');
return [];
}
}
/// 聚合会议统计
///
/// 从[daily]中聚合会议统计数据。
MeetingAsrHistoryStats aggregateMeetingStats(
List<MeetingAsrDailyStats> daily) {
int calls = 0;
int audioSeconds = 0;
int audioBytes = 0;
int transcriptBytes = 0;
for (final d in daily) {
calls += d.asrCalls;
audioSeconds += d.audioSecondsTotal;
audioBytes += d.audioBytesTotal;
transcriptBytes += d.transcriptBytesTotal;
}
Logger.i('MeetingASRrecord',
'聚合会议统计: calls=${calls}, audioSeconds=${audioSeconds}, audioBytes=${audioBytes}, transcriptBytes=${transcriptBytes}');
return MeetingAsrHistoryStats(
userId: getCurrentUserId(),
allAsrCalls: calls,
allAudioSeconds: audioSeconds,
allAudioFileBytes: audioBytes,
allTranscriptBytes: transcriptBytes,
);
}
/// 获取会议对象存储历史统计
///
/// 从[startDate]到[endDate]的会议对象存储上传记录。
Future<List<MeetingStorageDailyStats>> getMeetingStorageHistoryStats({
required DateTime startDate,
required DateTime endDate,
}) async {
try {
final List<MeetingStorageDailyStats> list = [];
for (DateTime date = startDate;
date.isBefore(endDate) || date.isAtSameMomentAs(endDate);
date = date.add(const Duration(days: 1))) {
final key = _formatDate(date);
final raw = _storage.read('${_meetingOsDailykey}_$key');
List<MeetingObjectStorageRecord> uploads = [];
if (raw is List) {
uploads = raw
.map((e) => MeetingObjectStorageRecord.fromJson(
Map<String, dynamic>.from(e)))
.toList();
}
if (uploads.isNotEmpty) {
list.add(MeetingStorageDailyStats(
date: key, userId: getCurrentUserId(), items: uploads));
}
}
Logger.i('MeetingOSrecord',
'获取会议对象存储历史: start=${_formatDate(startDate)}, end=${_formatDate(endDate)}, 有效天数=${list.length}');
return list;
} catch (e) {
Logger.error('获取对象存储历史统计失败: $e');
return [];
}
}
MeetingStorageHistoryStats aggregateMeetingStorageStats(
List<MeetingStorageDailyStats> daily) {
int uploads = 0;
int storageBytes = 0;
int transferBytes = 0;
for (final d in daily) {
uploads += d.storageUploads;
storageBytes += d.storageBytesTotal;
transferBytes += d.transferBytesTotal;
}
Logger.i('MeetingOSrecord',
'聚合对象存储统计: uploads=${uploads}, storageBytes=${storageBytes}, transferBytes=${transferBytes}');
return MeetingStorageHistoryStats(
userId: getCurrentUserId(),
allStorageUploads: uploads,
allStorageBytes: storageBytes,
allTransferBytes: transferBytes,
);
}
}

140
lib/data/services/version_update_service.dart

@ -26,14 +26,15 @@ class VersionUpdateService extends GetxService {
static String? _updateUrl = ""; //更新链接
static AppInfo? _appInfo; //应用信息
static bool? _isShowTourists = false; //是否显示游客登录
static bool? _allowSkipDeviceBinding = false; //是否允许跳过设备绑定
static DateTime? _lastCheckTime; //上次检查时间
static const int _cacheIntervalMinutes = 10; // 可配置化
static final String? _countryCode = Get.deviceLocale?.countryCode; //国家地区编码
static final String? _languageCode = Get.deviceLocale?.languageCode; //语言编码
// ignore: non_constant_identifier_names
static final String? _SERVER_URL = (_countryCode == 'CN')
? dotenv.env['SERVER_URL']
: dotenv.env['HW_SERVER_URL']; //服务器地址
// static final String? _SERVER_URL = (_countryCode == 'CN')
// ? dotenv.env['SERVER_URL']
// : dotenv.env['HW_SERVER_URL']; //服务器地址
// 添加 getter 方法来访问缓存的静态数据
/// 获取缓存的应用版本
@ -73,6 +74,9 @@ class VersionUpdateService extends GetxService {
/// 获取缓存的游客登录状态
bool get cachedShowTourists => _isShowTourists ?? false;
/// 获取缓存的是否允许跳过设备绑定
bool get cachedAllowSkipDeviceBinding => _allowSkipDeviceBinding ?? false;
/// 获取上次检查时间
DateTime? get lastCheckTime => _lastCheckTime;
@ -83,7 +87,7 @@ class VersionUpdateService extends GetxService {
String get cachedLanguageCode => _languageCode ?? '';
/// 获取缓存的服务器地址
String get cachedServerUrl => _SERVER_URL ?? '';
// String get cachedServerUrl => _SERVER_URL ?? '';
final Logger _logger = Logger();
@ -120,15 +124,15 @@ class VersionUpdateService extends GetxService {
//_channel = platformInfo.channel;
_lastCheckTime = DateTime.now();
// 调用后端接口获取最新版本信息
final response =
await Api.getChannelApp({'channel': platformInfo.channel.value});
// 获取所有渠道包信息
final response = await Api.getChannelApps();
_logger.d('lxm--获取所有渠道包信息:$response');
_logger.d('lxm--获取渠道包信息:$response');
final List<AppInfo> apps = _parseAppsList(response);
if (response == null || !response.containsKey('app')) {
//[2]获取渠道包信息失败: 响应为空或不包含app字段
_logger.w('lxm--获取渠道包信息失败: 响应为空或不包含app字段');
if (apps.isEmpty) {
_logger.w('lxm--获取所有渠道包信息失败或为空');
return VersionUpdateInfo(
hasUpdate: false,
currentVersion: currentVersion,
@ -137,22 +141,38 @@ class VersionUpdateService extends GetxService {
);
}
//final channelAppResponse = ChannelAppResponse.fromJson(response);
// 直接从response中获取app信息
final appInfo = AppInfo.fromJson(response['app']);
_appInfo = appInfo;
_logger.d('获取到的最新版本信息: ${appInfo.toJson()}');
_latestVersion = appInfo.version;
_updateUrl = appInfo.address;
final Map<UserChannel, AppInfo> appIndex = _buildChannelIndex(apps);
// 设置游客登录显示状态(先用当前渠道结果作为回退,再用.env渠道覆盖以保持一致)
_isShowTourists = appInfo.tourists;
//print('lxm--_isShowTourists: $_isShowTourists');
if (Platform.isAndroid && _channel != platformInfo.channel) {
//[4]当前渠道与.env渠道不同,需要从.env渠道获取游客登录配置
await _refreshTouristsFromEnv();
// 依据设备品牌渠道用于版本更新链接
final brandChannel = platformInfo.channel;
// 环境变量渠道用于游客登录配置
final envChannelName = dotenv.env['Channel'] ?? 'OFFICIAL';
final envChannel = UserChannel.fromName(envChannelName);
final AppInfo? envAppInfo = appIndex[envChannel];
// 若不存在品牌渠道信息,降级为环境渠道;仍不存在则返回无更新
final AppInfo? chosenAppInfo =
_getChannelAppInfo(appIndex, brandChannel, envChannel);
if (chosenAppInfo == null) {
_logger.w('lxm--未找到品牌或环境渠道的应用信息,返回无更新');
return VersionUpdateInfo(
hasUpdate: false,
currentVersion: currentVersion,
latestVersion: currentVersion,
updateType: UpdateType.none,
);
}
_appInfo = chosenAppInfo;
_latestVersion = chosenAppInfo.version;
_updateUrl = chosenAppInfo.address;
// 设置游客登录显示状态(先用当前渠道结果作为回退,再用.env渠道覆盖以保持一致)
_isShowTourists = (envAppInfo ?? chosenAppInfo).tourists;
_allowSkipDeviceBinding =
(envAppInfo ?? chosenAppInfo).allowskipdevicebinding;
_logger.d('lxm--从服务器获取游客登录配置(最终): ${_isShowTourists}');
// if (channelAppResponse.code != 0 || channelAppResponse.data == null) {
@ -166,20 +186,21 @@ class VersionUpdateService extends GetxService {
// }
// final appInfo = channelAppResponse.data!.app;
_hasUpdate = _compareVersions(currentVersion, appInfo.version);
_hasUpdate = _compareVersions(currentVersion, chosenAppInfo.version);
// 判断更新类型:如果主版本号不同则强制更新
UpdateType updateType = UpdateType.none;
if (_hasUpdate!) {
_isForceUpdate = _shouldForceUpdate(currentVersion, appInfo.version);
_isForceUpdate =
_shouldForceUpdate(currentVersion, chosenAppInfo.version);
updateType = _isForceUpdate! ? UpdateType.force : UpdateType.optional;
}
//[3]返回版本更新信息
return VersionUpdateInfo(
hasUpdate: _hasUpdate!,
currentVersion: currentVersion.split('+')[0],
latestVersion: appInfo.version.split('+')[0],
appInfo: appInfo,
latestVersion: chosenAppInfo.version.split('+')[0],
appInfo: chosenAppInfo,
updateType: updateType,
);
} catch (e) {
@ -289,30 +310,6 @@ class VersionUpdateService extends GetxService {
}
}
/// 从.env文件刷新游客登录配置
Future<void> _refreshTouristsFromEnv() async {
try {
final envChannelName = dotenv.env['Channel'];
if (envChannelName == null || envChannelName.isEmpty) {
_logger.w('未配置.env Channel,沿用当前渠道的游客配置: ${_isShowTourists}');
return;
}
final envChannel = UserChannel.fromName(envChannelName);
final resp = await Api.getChannelApp({'channel': envChannel.value});
if (resp != null && resp.containsKey('app')) {
final envAppInfo = AppInfo.fromJson(resp['app']);
_isShowTourists = envAppInfo.tourists;
_logger.d(
'lxm--游客登录配置已按.env渠道同步: ${envAppInfo.tourists} (channel=$envChannelName),_isShowTourists: $_isShowTourists');
} else {
_logger.w('按.env渠道获取游客配置失败:响应为空或不含app字段');
}
} catch (e) {
_logger.w('按.env渠道同步游客配置失败: $e');
}
}
/// 获取iOS设备品牌信息
Future<void> _getIosDeviceBrand() async {
try {
@ -405,6 +402,45 @@ class VersionUpdateService extends GetxService {
return latestVersions.length > currentVersions.length;
}
/// 解析响应数据为AppInfo列表
List<AppInfo> _parseAppsList(dynamic response) {
try {
final appsJson = (response is Map) ? response['apps'] : null;
if (appsJson is List) {
return appsJson
.whereType<Map<String, dynamic>>()
.map((e) => AppInfo.fromJson(e))
.toList();
}
} catch (e) {
_logger.e('解析渠道列表失败: $e');
}
return [];
}
/// 构建渠道索引
Map<UserChannel, AppInfo> _buildChannelIndex(List<AppInfo> apps) {
final index = <UserChannel, AppInfo>{};
for (final app in apps) {
index[app.channel] = app;
}
return index;
}
/// 获取渠道信息,带备选策略
///
/// 优先返回主渠道的信息,如果主渠道不存在则返回备选渠道的信息。
/// 主要用于:
/// 1. 版本更新:优先使用设备品牌渠道,备选使用环境变量渠道
/// 2. 功能配置:优先使用环境变量渠道,备选使用版本更新渠道
AppInfo? _getChannelAppInfo(
Map<UserChannel, AppInfo> index,
UserChannel primary,
UserChannel? fallback,
) {
return index[primary] ?? (fallback != null ? index[fallback] : null);
}
/// 解析版本号字符串为数字数组
List<int> _parseVersion(String version) {
final parts = version.split('.');

11
lib/data/services/volcano_translation_service.dart

@ -165,7 +165,12 @@ class VolcanoTranslationService extends GetxService {
};
}
// 翻译文本
// 文本翻译
/// [text] 待翻译的文本
/// [sourceLanguageCode] 源语言的ASR代码
/// [targetLanguageCode] 目标语言的ASR代码
/// [return] 翻译后的文本
/// 计费标准:每月200万字符免费,超出部分按49元/百万字符计费
Future<String?> translateText({
required String text,
required String sourceLanguageCode,
@ -417,6 +422,10 @@ class VolcanoTranslationService extends GetxService {
}
/// 图片翻译(整图识别+回贴翻译)
/// [imageBytes] 待翻译的图片二进制数据
/// [targetLanguageCode] 目标语言的ASR代码
/// [return] 翻译结果
/// 计费标准:每月100张免费,超出部分按0.04元/张计费
Future<ImageTranslationResult?> translateImage({
required Uint8List imageBytes,
required String targetLanguageCode, // ASR代码,如 zh-CN / en-US

41
lib/modules/agent/controllers/agent_controller.dart

@ -13,6 +13,7 @@ import '/data/services/bluetooth_manager.dart';
import '/data/services/qq_music.dart';
import 'package:flutter_intro/flutter_intro.dart';
import '../../../data/services/novice_guide_service.dart';
import '../../../routes/app_routes.dart';
import '/core/utils/upload_oss.dart';
import '/data/models/user_Info.dart';
import '/data/services/music_manager.dart';
@ -30,6 +31,7 @@ import 'package:path_provider/path_provider.dart';
import 'package:photo_view/photo_view.dart';
import '../../../core/utils/permission_util.dart';
import '../../../data/models/message_model.dart';
import '../../common/widgets/recharge_dialog.dart';
// 语音输入模式枚举
enum VoiceInputMode {
@ -45,7 +47,7 @@ class AgentController extends GetxController with WidgetsBindingObserver {
// 聊天消息列表
final messages = <Message>[].obs;
final currsessionid = ''.obs;
final vipExpiryTime = 0.obs;
// UI控制器
final TextEditingController textController = TextEditingController();
final ScrollController scrollController = ScrollController();
@ -165,6 +167,10 @@ class AgentController extends GetxController with WidgetsBindingObserver {
@override
void onInit() {
super.onInit();
vipExpiryTime.value = User.isLoggedIn() ? User.instance.vipexptime : 0;
ever<int>(User.refreshTick, (_) {
vipExpiryTime.value = User.instance.vipexptime;
});
_initAppDir();
_loadTtsPreference(); //加载TTS偏好设置
_loadTtsInterrupe(); //加载TTS播报打断偏好设置
@ -550,7 +556,7 @@ class AgentController extends GetxController with WidgetsBindingObserver {
messages.add(Message(
sessionid: "", // 会话ID
isUser: false,
text: 'welcomeMessage'.tr, // 你好!我是**小言**,我能帮你:
text: 'welcomeMessage'.tr, // 你好!我是**Lily**,我能帮你:
));
}
@ -626,15 +632,15 @@ class AgentController extends GetxController with WidgetsBindingObserver {
final text = event.data['text'] ?? '';
Logger.i(TAG, '[$sessionid]识别最终结果: $text');
if (currsessionid.value != "" && currsessionid.value != sessionid) {
final index = messages.lastIndexWhere(
(msg) => msg.sessionid == currsessionid.value && msg.isUser);
//出现了为识别结束的消息
if (index >= 0) {
//异除去当前会话的识别中消息
messages.removeAt(index);
}
}
// if (currsessionid.value != "" && currsessionid.value != sessionid) {
// final index = messages.lastIndexWhere(
// (msg) => msg.sessionid == currsessionid.value && msg.isUser);
// //出现了为识别结束的消息
// if (index >= 0) {
// //异除去当前会话的识别中消息
// messages.removeAt(index);
// }
// }
currsessionid.value = sessionid;
// 查找是否有正在识别中的消息
final index = messages.lastIndexWhere(
@ -781,9 +787,9 @@ class AgentController extends GetxController with WidgetsBindingObserver {
case AgentServiceEventType.error:
final sessionid = event.data['sessionid'] ?? '';
final message = event.data['message'] ?? '';
final code = event.data['code'] ?? 0;
// //验证错误码
if (event.data['code'] == 1000) {
if (code == 1000) {
isListening.value = false;
isSpeaking.value = false;
isProcessing.value = false;
@ -797,6 +803,10 @@ class AgentController extends GetxController with WidgetsBindingObserver {
}
}
Get.snackbar('error'.tr, '${event.data['message']}');
} else if (code == 2001) {
// 余额不足或需要充值,给出弹窗确认是否跳转充值界面
showRechargeDialog('agent');
}
Logger.e(TAG, '代理服务错误: ${event.data['message']}');
break;
@ -1019,6 +1029,11 @@ class AgentController extends GetxController with WidgetsBindingObserver {
// }
}
break;
case AgentServiceEventType.assistantUsages:
final sessionid = event.data['sessionid'] ?? '';
final integral = event.data['integral'] ?? 0;
User.instance.aichatintegral = integral;
break;
default:
break;
}

66
lib/modules/agent/views/agent_view.dart

@ -6,12 +6,14 @@ import 'package:flutter_intro/flutter_intro.dart';
import 'package:get/get.dart';
import 'package:haptic_feedback/haptic_feedback.dart';
import '../../../core/widgets/intro_overlay_builder.dart';
import '../../../data/models/user_Info.dart';
import '../controllers/agent_controller.dart';
import '../controllers/message_action_controller.dart';
import 'message_bubble.dart';
import '../widgets/full_screen_editor.dart';
import '../widgets/sound_bar_widget.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:intl/intl.dart';
class AgentView extends StatefulWidget {
const AgentView({Key? key}) : super(key: key);
@ -90,7 +92,7 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
],
),
child: Icon(
Icons.smart_toy_outlined,
Icons.support_agent,
color: Colors.white,
size: 22.sp,
),
@ -100,7 +102,7 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'XiaoYan'.tr,
'Lily'.tr,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.bold,
@ -118,14 +120,27 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
),
),
SizedBox(width: 4.w),
Text(
'online'.tr,
style: TextStyle(
fontSize: 12.sp,
color: Colors.green,
fontWeight: FontWeight.w500,
),
),
Obx(() {
final vipexptime = controller.vipExpiryTime.value;
DateTime? expiry;
if (vipexptime > 0) {
expiry = vipexptime > 1000000000000
? DateTime.fromMillisecondsSinceEpoch(vipexptime)
: DateTime.fromMillisecondsSinceEpoch(
vipexptime * 1000);
}
final text = expiry != null
? '${'expiryLabel'.tr}${DateFormat('yyyy-MM-dd').format(expiry)}'
: 'notActivated'.tr;
return Text(
text,
style: TextStyle(
fontSize: 12.sp,
color: Colors.green,
fontWeight: FontWeight.w500,
),
);
}),
],
),
],
@ -275,8 +290,8 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
params,
false,
title: controller.newAIReplyCompleted.value
? '小言已经完成了回答!'
: '小言正在思考中~',
? 'aiReplyCompleted'.tr
: 'aiThinking'.tr,
onNext: controller.newAIReplyCompleted.value ? () {} : null,
),
);
@ -327,9 +342,8 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
overlayBuilder: (params) {
return IntroOverlayBuilder.aiBuilder(
params,
controller.noviceGuideService.aiStepsList[
controller.noviceGuideService
.aiStep]['end'],
'${controller.noviceGuideService.aiStepsList[controller.noviceGuideService.aiStep]['endKey']}'
.tr,
onFinish: () async {
if (controller
.noviceGuideService.aiStep <
@ -620,24 +634,18 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
overlayBuilder: (params) {
return IntroOverlayBuilder.aiBuilder(
params,
controller
.noviceGuideService.aiStepsList[
controller.noviceGuideService
.aiStep]['start'],
buttonText: '确定输入',
'${controller.noviceGuideService.aiStepsList[controller.noviceGuideService.aiStep]['startKey']}'
.tr,
buttonText: 'confirmInput'.tr,
onNext: () {
controller.textController.text =
controller.noviceGuideService
.aiStepsList[
controller.noviceGuideService
.aiStep]['input'];
'${controller.noviceGuideService.aiStepsList[controller.noviceGuideService.aiStep]['inputKey']}'
.tr;
},
onTap: () {
controller.textController.text =
controller.noviceGuideService
.aiStepsList[
controller.noviceGuideService
.aiStep]['input'];
'${controller.noviceGuideService.aiStepsList[controller.noviceGuideService.aiStep]['inputKey']}'
.tr;
params.onNext!();
},
);
@ -861,7 +869,7 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
overlayBuilder: (params) {
return IntroOverlayBuilder.aiBuilder(
params,
'点击发送,${controller.noviceGuideService.aiStepsList[controller.noviceGuideService.aiStep]['send']}',
'${'guideClickSendPrefix'.tr}${'${controller.noviceGuideService.aiStepsList[controller.noviceGuideService.aiStep]['sendKey']}'.tr}',
alignment: false,
onTap: () async {
await controller

5
lib/modules/agent/views/message_bubble.dart

@ -166,6 +166,7 @@ class MessageBubble extends GetView<AgentController> {
// 如果是识别中的消息,添加特殊样式
if (isRecognizing) {
return Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
@ -177,7 +178,9 @@ class MessageBubble extends GetView<AgentController> {
fontSize: 14,
height: 1.4,
),
overflow: TextOverflow.ellipsis,
// 允许自动换行,不再强制单行
softWrap: true,
maxLines: null,
),
),
const SizedBox(width: 8),

2
lib/modules/common/widgets/language_selector_bar.dart

@ -58,7 +58,7 @@ class LanguageSelectorBar extends StatelessWidget {
isDarkMode ? AppColors.primary.withOpacity(0.2) : Colors.blue[50];
final swapIconColor = isDarkMode ? AppColors.primary : Colors.blue;
// 规范化特殊项的翻译键,例如:自动检测 -> autoDetect(翻译键代表的中文文本内容)
// 规范化特殊项的翻译键,例如:自动检测 -> autoDetect(对应中文:自动检测)
String _normalizeKey(String text) {
switch (text) {
case '自动检测':

73
lib/modules/common/widgets/recharge_dialog.dart

@ -0,0 +1,73 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../routes/app_routes.dart';
/// 显示充值弹窗
/// [type] 充值类型,可选值为 'agent'、'translation'、'meeting'
/// 分别跳转对应ai充值、翻译充值、会议充值界面
void showRechargeDialog(String type) {
Get.dialog(
Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Stack(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(16, 20, 16, 16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'tip'.tr,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 12),
Text(
(type == 'agent'
? 'aiMemberExpiredDesc'
: 'insufficientBalanceDesc')
.tr, // 会员过期描述 / 余额不足描述
textAlign: TextAlign.center,
),
const SizedBox(height: 20),
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.orangeAccent,
foregroundColor: Colors.white,
),
onPressed: () {
Get.back();
if (type == 'agent') {
Get.toNamed(Routes.goodsvip);
} else if (type == 'translation') {
Get.toNamed(Routes.goodstrans);
} else if (type == 'meeting') {
Get.toNamed(Routes.goodsmeet);
}
},
child: Text('recharge'.tr),
),
),
],
),
),
Positioned(
right: 8,
top: 8,
child: IconButton(
icon: const Icon(Icons.close),
onPressed: () => Get.back(),
),
),
],
),
),
barrierDismissible: true,
);
}

2
lib/modules/devices/controllers/devices_controller.dart

@ -1,4 +1,4 @@
import 'dart:ffi';
// import 'dart:ffi'; // Not supported on web; not needed here
import '/data/models/appconfig_model.dart';

171
lib/modules/devices/views/devices_view.dart

@ -1,5 +1,6 @@
import 'dart:ui';
import '../../../routes/app_routes.dart';
import '/modules/devices/controllers/devices_controller.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
@ -201,103 +202,107 @@ class DevicesView extends GetView<DevicesController> {
required DeviceType deviceType,
required bool isDarkMode,
}) {
return Container(
margin: EdgeInsets.only(bottom: 12.h),
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: isDarkMode ? AppColors.cardBackground : Colors.white,
borderRadius: BorderRadius.circular(12.r),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Row(
children: [
// 设备图标
Container(
width: 48.w,
height: 48.w,
decoration: BoxDecoration(
color:
isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[100],
borderRadius: BorderRadius.circular(12.r),
return GestureDetector(
onTap: () => Get.toNamed(Routes.eqSettings),
child: Container(
margin: EdgeInsets.only(bottom: 12.h),
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: isDarkMode ? AppColors.cardBackground : Colors.white,
borderRadius: BorderRadius.circular(12.r),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 8,
offset: const Offset(0, 2),
),
child: Icon(
deviceType.icon,
color: isDarkMode ? Colors.white : Colors.black87,
size: 24.sp,
],
),
child: Row(
children: [
// 设备图标
Container(
width: 48.w,
height: 48.w,
decoration: BoxDecoration(
color: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[100],
borderRadius: BorderRadius.circular(12.r),
),
child: Icon(
deviceType.icon,
color: isDarkMode ? Colors.white : Colors.black87,
size: 24.sp,
),
),
),
SizedBox(width: 16.w),
// 设备信息
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
device.devicename.isNotEmpty
? device.devicename
: "deviceTypeUnknown".tr,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.white : Colors.black87,
),
),
SizedBox(height: 4.h),
Text(
device.devicemac.isNotEmpty
? device.devicemac
: "noMacAddress".tr,
style: TextStyle(
fontSize: 14.sp,
color: isDarkMode ? Colors.white70 : Colors.grey[600],
SizedBox(width: 16.w),
// 设备信息
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
device.devicename.isNotEmpty
? device.devicename
: "deviceTypeUnknown".tr,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.white : Colors.black87,
),
),
),
if (device.license.isNotEmpty) ...[
SizedBox(height: 4.h),
Text(
"${"licenseCode".tr}: ${device.license}",
device.devicemac.isNotEmpty
? device.devicemac
: "noMacAddress".tr,
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white54 : Colors.grey[500],
fontSize: 14.sp,
color: isDarkMode ? Colors.white70 : Colors.grey[600],
),
),
if (device.license.isNotEmpty) ...[
SizedBox(height: 4.h),
Text(
"${"licenseCode".tr}: ${device.license}",
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white54 : Colors.grey[500],
),
),
],
],
],
),
),
// 解绑按钮
GestureDetector(
onTap: () => _showUnbindDialog(device, isDarkMode),
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 12.w,
vertical: 6.h,
),
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.1),
borderRadius: BorderRadius.circular(6.r),
border: Border.all(
color: Colors.red.withOpacity(0.3),
width: 1,
),
// 解绑按钮
GestureDetector(
onTap: () => _showUnbindDialog(device, isDarkMode),
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 12.w,
vertical: 6.h,
),
),
child: Text(
"unbind".tr,
style: TextStyle(
fontSize: 12.sp,
color: Colors.red,
fontWeight: FontWeight.w500,
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.1),
borderRadius: BorderRadius.circular(6.r),
border: Border.all(
color: Colors.red.withOpacity(0.3),
width: 1,
),
),
child: Text(
"unbind".tr,
style: TextStyle(
fontSize: 12.sp,
color: Colors.red,
fontWeight: FontWeight.w500,
),
),
),
),
),
],
],
),
),
);
}

10
lib/modules/eq_settings/bindings/eq_settings_binding.dart

@ -0,0 +1,10 @@
import 'package:get/get.dart';
import '../controllers/eq_settings_controller.dart';
class EqSettingsBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut<EqSettingsController>(() => EqSettingsController());
}
}

217
lib/modules/eq_settings/controllers/eq_settings_controller.dart

@ -0,0 +1,217 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import '../../../core/utils/logger.dart';
import '../../../routes/app_routes.dart';
import '../views/widgets/row_confirm_widget.dart';
import '../views/widgets/row_equalizer_widget.dart';
import '../views/widgets/row_grade_widget.dart';
import '../views/widgets/row_input_widget.dart';
import '../views/widgets/row_keypress_widget.dart';
import '../views/widgets/row_radio_widget.dart';
import '../views/widgets/row_switch_widget.dart';
import '../views/widgets/row_timer_widget.dart';
class EqSettingsController extends GetxController {
final RxList uiList = [
{
'title': '音效',
'templates': [
{
'type': 'equalizer',
'name': '均衡器',
'value': [],
'options': [
{
'label': '默认',
'value': [1, 2, 3, 4, 5, 4, 3, 2, 1, 0],
'default': true,
},
{
'label': '流行',
'value': [1, 0, 3, 4, 5, 4, 1, 2, 1, 0],
'default': true,
},
{
'label': '摇滚',
'value': [2, 3, 4, 5, 4, 3, 2, 1, 0, -1],
'default': true,
},
{
'label': '爵士',
'value': [3, 4, 0, 4, 3, 2, 1, 0, -1, -2],
'default': true,
},
{
'label': '经典',
'value': [3, 4, 2, 4, 3, 2, 1, 0, -1, -2],
'default': true,
},
{
'label': '乡村',
'value': [3, 4, 1, 4, 3, 2, 1, 0, -1, -2],
'default': true,
},
],
'xAxis': [
'8',
'31',
'62',
'125',
'250',
'500',
'1K',
'2K',
'4K',
'16K'
],
'onCallback': (List value) {
Logger.d('equalizer', '均衡器:$value');
},
}
],
},
{
'title': '按键功能',
'templates': [
{
'type': 'keypress',
'data': [
{'key': 'key1', 'label': '单击', 'left': 1, 'right': 1},
{'key': 'key2', 'label': '双击', 'left': 1, 'right': 1},
{'key': 'key3', 'label': '三击', 'left': 1, 'right': 1},
{'key': 'key4', 'label': '长按', 'left': 1, 'right': 1},
],
'options': [
{'label': '无作用', 'value': 0},
{'label': '回拨电话', 'value': 1},
{'label': '语音助手', 'value': 2},
{'label': '上一曲', 'value': 3},
{'label': '下一曲', 'value': 4},
{'label': '音量加', 'value': 5},
{'label': '音量减', 'value': 6},
{'label': '播放暂停', 'value': 7},
{'label': '游戏模式', 'value': 8},
{'label': '降噪设置', 'value': 9},
{'label': 'EQ切换', 'value': 10},
],
'onCallback': (Map value) {
Logger.d('keypress', '按键功能:$value');
},
},
],
},
{
'title': '耳机功能',
'templates': [
{
'type': 'input',
'name': '修改名称',
'value': 'voitrans',
'onCallback': (String value) {
Logger.d('input', '修改名称:$value');
},
},
{
'type': 'radio',
'name': '工作模式',
'value': 1,
'options': [
{'label': '游戏模式', 'value': 1},
{'label': '娱乐模式', 'value': 2},
{'label': '睡眠模式', 'value': 3},
],
'onCallback': (int value) {
Logger.d('radio', '工作模式:$value');
},
},
{
'type': 'switch',
'name': '闪灯开关',
'value': false,
'onCallback': (bool value) {
Logger.d('switch', '闪灯开关:$value');
},
},
{
'type': 'switch',
'name': '查找设备',
'value': false,
'description': '在设备上播放声音',
'onCallback': (bool value) {
Logger.d('switch', '查找设备:$value');
},
},
{
'type': 'grade',
'name': '降噪等级',
'value': 0,
'onCallback': (int value) {
Logger.d('grade', '降噪等级:$value');
},
},
{
'type': 'timer',
'name': '定时关机',
'value': 0,
'onCallback': (int value) {
Logger.d('timer', '定时关机:$value');
},
},
],
},
{
'templates': [
{
'type': 'confirm',
'name': '升级耳机固件',
'onCallback': () => Get.toNamed(Routes.OTA_UPGRADE),
},
{
'type': 'confirm',
'name': '恢复出厂设置',
'tips': '确定要恢复出厂设置吗?',
'onCallback': () {
Logger.d('confirm', '恢复出厂设置');
},
},
{
'type': 'confirm',
'name': '清除配对记录',
'tips': '确定要清除配对记录吗?',
'onCallback': () {
Logger.d('confirm', '清除配对记录');
},
},
],
}
].obs;
final GetStorage _storage = GetStorage();
@override
void onInit() {
super.onInit();
final List equalizerOptions = _storage.read('equalizer_options') ?? [];
if (equalizerOptions.isNotEmpty) {
List options =
equalizerOptions.map((e) => Map<String, Object>.from(e)).toList();
uiList[0]['templates'][0]['options'].addAll(options);
}
}
Widget getTemplate(Map data) {
return switch (data['type']) {
'equalizer' => RowEqualizerWidget(data),
'keypress' => RowKeypressWidget(data),
'input' => RowInputWidget(data),
'radio' => RowRadioWidget(data),
'switch' => RowSwitchWidget(data),
'grade' => RowGradeWidget(data),
'timer' => RowTimerWidget(data),
'confirm' => RowConfirmWidget(data),
_ => const SizedBox.shrink(),
};
}
}

95
lib/modules/eq_settings/views/eq_settings_view.dart

@ -0,0 +1,95 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import '../controllers/eq_settings_controller.dart';
class EqSettingsView extends GetView<EqSettingsController> {
const EqSettingsView({super.key});
@override
Widget build(BuildContext context) {
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
return Scaffold(
backgroundColor: isDarkMode ? Colors.black : Colors.grey[50],
appBar: _buildAppBar(isDarkMode),
body: _buildBody(isDarkMode),
);
}
// 构建应用栏
PreferredSizeWidget _buildAppBar(bool isDarkMode) {
return AppBar(
backgroundColor: isDarkMode ? Colors.black : Colors.white,
surfaceTintColor: Colors.transparent,
elevation: 0.5,
leading: IconButton(
icon: Icon(
Icons.arrow_back_ios,
color: isDarkMode ? Colors.white : Colors.black,
size: 20.sp,
),
onPressed: () => Get.back(),
),
title: Text(
'设备设置',
style: TextStyle(
fontSize: 17.sp,
fontWeight: FontWeight.w600,
color: isDarkMode ? Colors.white : Colors.black,
),
),
centerTitle: true,
);
}
// 构建主体内容
Widget _buildBody(bool isDarkMode) {
return Obx(
() => ListView.builder(
itemCount: controller.uiList.length,
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 5.w),
itemBuilder: (BuildContext context, int index) {
Map data = controller.uiList[index];
return _item(isDarkMode, data);
},
),
);
}
Widget _item(bool isDarkMode, Map data) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 15.w, vertical: 10.w),
margin: EdgeInsets.symmetric(vertical: 5.w),
decoration: BoxDecoration(
color: isDarkMode ? Colors.white.withValues(alpha: 0.05) : Colors.white,
borderRadius: BorderRadius.circular(8.w),
boxShadow: [
BoxShadow(
color: isDarkMode
? Colors.black.withValues(alpha: 0.2)
: Colors.black.withValues(alpha: 0.05),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (data['title'] != null)
Text(
data['title'],
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
color: isDarkMode ? Colors.white : Colors.black,
),
),
...data['templates'].map((e) => controller.getTemplate(e)).toList(),
],
),
);
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save