Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
.dart_tool/
.packages
build/
release/
*.apk
*.aab
# If you're building an application, you may want to check-in your pubspec.lock
pubspec.lock

Expand All @@ -28,12 +31,8 @@ doc/api/
lib/firebase_options.dart
*.exe
android/app/google-services.json
.idea/caches/deviceStreaming.xml
.idea/caches/deviceStreaming.xml
.idea/deviceManager.xml
.idea/caches/
firebase.json
.idea/deviceManager.xml
android/.kotlin/sessions/kotlin-compiler-11069125661880765564.salive
.idea/caches/deviceStreaming.xml
.idea/deviceManager.xml
android/.kotlin/
/.tmp.driveupload
16 changes: 11 additions & 5 deletions android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,23 @@ android {

signingConfigs {
create("release") {
keyAlias = keystoreProperties["keyAlias"] as String
keyPassword = keystoreProperties["keyPassword"] as String
storeFile = keystoreProperties["storeFile"]?.let { file(it) }
storePassword = keystoreProperties["storePassword"] as String
if (keystorePropertiesFile.exists()) {
keyAlias = keystoreProperties["keyAlias"] as String
keyPassword = keystoreProperties["keyPassword"] as String
storeFile = keystoreProperties["storeFile"]?.let { file(it) }
storePassword = keystoreProperties["storePassword"] as String
}
}
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.getByName("release")
signingConfig = if (keystorePropertiesFile.exists()) {
signingConfigs.getByName("release")
} else {
signingConfigs.getByName("debug")
}
}
debug {
signingConfig = signingConfigs.getByName("debug")
Expand Down
4 changes: 2 additions & 2 deletions assets/additional_resources.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@
"type": "link",
"collection": "appdocs",
"name": "Application's Google Store page",
"value": "https://play.google.com/store/apps/details?id=page.puzzak.geminilocal"
"value": "https://play.google.com/store/apps/details?id=page.puzzak.paios"
},
{
"type": "link",
"collection": "appdocs",
"name": "Developer's Website",
"value": "https://puzzak.page"
}
]
]
5 changes: 5 additions & 0 deletions assets/translations/languages.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
"name": "Traditional Chinese",
"id": "zh"
},
{
"origin": "简体中文",
"name": "Simplified Chinese",
"id": "zh-Hans"
},
{
"origin": "Deutsch",
"name": "German",
Expand Down
161 changes: 161 additions & 0 deletions assets/translations/zh-Hans.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
{
"add_lang": "与 AI 分享应用语言",
"add_lang_desc": "让模型使用该语言回答",
"add_time": "告诉模型日期和时间",
"add_time_desc": "将日期和时间加入指令",
"ai_may_not_differ_prompt_and_instructions": "模型可能无法区分提示词和指令。",
"appdocs": "应用链接",
"available": "可用",
"cancel_generate": "停止生成",
"clear_context": "删除聊天",
"context_desc": "~%c 个 Token",
"context_title": "上下文大小",
"continue": "继续",
"current_language": "简体中文",
"documentation": "ML Kit GenAI 文档",
"downloading_model": "正在下载模型",
"downloading_model_error": "无法下载模型",
"error_retry": "出错时重试",
"error_retry_desc": "生成出错时自动重试",
"generate": "生成",
"generated_hint": "已在 %seconds% 秒内回复,使用 %tokens% 个 Token(%tokenspersec% Token/秒)。",
"generating_hint": "正在生成,已用时 %seconds% 秒,使用 %tokens% 个 Token(%tokenspersec% Token/秒)。",
"gh_repo": "GitHub 仓库",
"ignore_instructions": "忽略所有指令",
"ignore_instructions_desc": "输出可能会变得很奇怪",
"in_play_store": "在 Play 商店中",
"instructions": "用户指令",
"instructions_desc": "系统提示词描述了模型的行为。你无法直接修改它,但可以在 GitHub 上建议更改。\n\n其中包含用户提示词,你可以编辑它。这会根据你的偏好微调模型行为。",
"language_settings": "语言",
"long_tap_clear": "长按确认",
"long_tap_cleared": "上下文已清除!",
"mock_gemini_1": "你好!我是 Flan-T5,一个 100% 在你的设备本地运行的 AI 模型。因为我始终在本机工作,所以你的数据会保持私密,并且我可以离线运行。",
"mock_gemini_2": "我可以帮助你完成各种任务,例如总结文本、头脑风暴、编写代码或回答复杂问题。",
"mock_gemini_3": "量子计算是一种利用量子物理来解决普通计算机难以处理的问题的计算方式。这个话题很有意思,虽然确实有点难理解!",
"mock_user_1": "你好!你是谁?",
"mock_user_2": "有意思。你能做什么?",
"mock_user_3": "好的,用一句简单的话解释“量子计算”。",
"model_available": "你可以使用 %s 模型",
"modeldocs": "模型文档",
"no_context_yet": "AI 早期访问版本。模型可能会出错,也可能不回复。",
"open_aicore_settings": "打开 AICore 设置",
"prompt": "在这里输入消息",
"prompt_hint": "例如:“介绍一下你自己。”",
"recommend_changes_gh": "你可以在 GitHub 仓库中建议更改",
"reset_model_context": "清除上下文",
"reset_model_params": "重置参数",
"reset_model_params_desc": "温度、Token",
"reset_model_prompt": "清除提示词",
"reset_model_prompt_desc": "不添加任何指令",
"reset_model_settings": "重置选项",
"select_language": "选择应用语言",
"select_language_auto_long": "或使用自动检测",
"settings": "设置",
"settings_ai": "模型参数",
"settings_ai_desc": "指令、参数、重置选项",
"settings_app": "应用设置",
"settings_info": "应用仍在开发中。请在 GitHub 上报告错误、翻译问题并留下任何反馈。\n\n由 Puzzak 于 %year% 年在乌克兰开发。\n\n荣耀归于乌克兰!",
"settings_resources": "附加资源",
"settings_resources_desc": "文档、链接、信息",
"settings_status": "模型状态",
"share": "分享",
"shared_data": "附加数据",
"system_prompt": "模型指令",
"system_prompt_desc": "系统提示词、指令",
"tap_to_open": "点按打开",
"temperature": "温度",
"title": "PAIOS",
"tokens": "每次回复的 Token 数",
"unavailable": "不可用",
"waiting_engine": "正在检查模型可用性",
"waiting_for_AI": "正在等待模型开始生成。如果这条消息显示时间超过预期,可能是 ML Kit 发生了错误,或者你已达到配额限制(这种情况下请等待一分钟后再试)。",
"waiting_network": "AI Core 正在等待 WiFi",
"welcome": "模拟聊天。\n请记住,AI 可能会出错,也可能忽略你的请求。可以在设置中查看更多信息。\n希望你喜欢这次体验 - Puzzak :)",
"welcome_available": "这些设置是新聊天的默认值,你也可以为每个聊天单独配置。",
"welcome_download": "AI Core 正在下载模型,下载完成后你就可以离线使用它。通常模型大小约为 %size%,但具体取决于设备和模型版本。\n下载完成后,AI Core 会在后台管理并更新模型。下载需要 WiFi。",
"welcome_gtfo": "模型正在后台下载。你可以关闭应用。\n如果关闭应用,将无法查看精确进度(只能看到正在下载、错误等状态)。",
"welcome_unavailable": "很遗憾,你的设备可能不支持此模型,或者应用无法使用 Google AICore。要查看更多信息、排查步骤或报告问题,请访问 GitHub 仓库。\n\n有关模型可用性的更多信息,请访问 MLKit GenAI 文档。",
"whoops": "点按检查 AI Core",
"years": "年",
"year": "年",
"months": "个月",
"month": "个月",
"days": "天",
"day": "天",
"hours": "小时",
"hour": "小时",
"minutes": "分钟",
"minute": "分钟",
"updated": "已更新",
"created": "已创建",
"ago": "前",
"just_now": "刚刚",
"chats": "聊天",
"your_chats": "聊天",
"other_chats": "其他聊天",
"pinned_chats": "已置顶",
"pinned_chats_desc": "如需置顶聊天,请前往该聊天的设置",
"new_chat": "新聊天",
"chat_settings": "聊天设置",
"chat_settings_other": "其他聊天设置",
"chat_settings_desc": "这些设置仅适用于当前聊天。要编辑全局参数,请打开设置。",
"chat_settings_subtitle": "前往设置",
"chat_name": "聊天名称",
"name_wrong": "无法保存此名称",
"previous_names": "之前的聊天名称",
"change_name": "点按更改名称",
"edit_name": "更改名称",
"pin_chat": "置顶聊天",
"pin_chat_desc": "固定到列表顶部",
"generating_title": "正在生成新名称...",
"loading": "正在加载...",
"messages": "条消息",
"no_chats": "你还没有开始任何聊天。按下方按钮开始。",
"chats_desc": "你有 %chatnum% 个聊天。点按“新聊天”按钮开始新的聊天。",
"still_generating": "AI 仍在生成。请等待这条消息更新后再与其他聊天互动。",
"analytics_title": "分析",
"analytics": "允许分析",
"analytics_desc": "收集匿名使用情况和应用问题数据",
"logs_with_analytics": "日志和分析",
"logs_no_analytics": "日志",
"logs_info_local": "这些是应用日志,仅保存在本地。本地日志不会在应用重启之间保留,它们用于帮助你了解后台正在发生什么。如果你愿意帮助我改进应用,可以启用分析。",
"logs_info_analytics": "这些是应用日志,会与开发者共享。本地日志不会在应用重启之间保留,它们用于帮助你了解后台正在发生什么。数据是匿名的,仅用于衡量应用指标和崩溃情况,以便改进应用。聊天名称、消息或任何可识别信息都不会发送到分析系统。感谢你帮助这个应用变得更好!",
"advancedlinks": "高级用户",
"New for 1.2.0": "以下部分包含 1.1.5 到 1.2.0 版本的字符串",
"create_prompt_custom": "创建自定义提示词",
"new_prompt_name": "新提示词",
"prompt_manager_title": "提示词管理器",
"default_prompts_title": "默认提示词",
"by_author": "作者:%author%",
"last_updated": "最后更新",
"close": "关闭",
"clone_prompt": "克隆",
"user_prompts_title": "用户提示词",
"no_user_prompts": "没有自定义提示词",
"no_user_prompts_desc": "点按此处创建一个",
"prompt_name": "提示词名称",
"prompt_content_hint": "在这里输入你的系统指令...",
"chat_prompt": "聊天提示词",
"select_prompt": "选择提示词",
"save": "保存",
"saved": "已保存!",
"delete": "删除",
"try_prompt": "试用此提示词",
"edit": "编辑",
"prompt_md_title": "支持 Markdown",
"prompt_md_desc": "你可以在提示词中使用 Markdown 格式。AI 会看到纯文本,但查看器会渲染格式。",
"prompt_md_docs_link": "GitHub Markdown 语法参考",
"prompt_manager_info": "选中的提示词会作为新聊天的系统指令。在此处更改不会影响现有对话。\n\n无论你选择哪个提示词,以下部分都会自动追加:\n• [SYSTEM INSTRUCTIONS]:包裹你的提示词文本\n• [CONTEXTUAL DATA]:当前时间和语言(如果已在聊天设置中启用)\n• [DATA & INSTRUCTION RULES]:根据上下文数据设置生成的规则\n• [CHAT HISTORY]:用于多轮回复的对话上下文",
"model_continuing": "正在继续回答...",
"new_chat_hold": "长按可在开始前配置",
"configure_new_chat": "配置此聊天",
"temperature_desc": "%value%,默认值为 0.7",
"prompt_description": "描述",
"prompt_author": "作者",
"prompt_last_updated": "最后更新",
"prompt_empty": "此提示词为空。",
"export_prompt": "导出为 .md",
"prompt_dir_title": "提示词文件目录",
"prompt_dir_none": "点按选择文件夹",
"prompt_dir_desc": "你可以将 .md 提示词保存到所选文件夹,以便在应用内使用,也可以在那里添加新提示词。"
}
2 changes: 0 additions & 2 deletions lib/engine.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'dart:async';
import 'dart:convert';

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/foundation.dart';
Expand Down Expand Up @@ -636,7 +635,6 @@ class AIEngine with md.ChangeNotifier {
status = "Sending prompt...";
notifyListeners();

final int runTokens = chatData.chats.containsKey(currentChat) && chatData.chats[currentChat].containsKey("chatTokens") ? chatData.chats[currentChat]["chatTokens"] : tokens;
double runTemperature = chatData.chats.containsKey(currentChat) && chatData.chats[currentChat].containsKey("chatTemperature") ? chatData.chats[currentChat]["chatTemperature"] : temperature;

final stream = gemini.generateTextEvents(
Expand Down
10 changes: 5 additions & 5 deletions lib/pages/chat.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ class ChatPage extends StatefulWidget {
}

class ChatPageState extends State<ChatPage> {
text tWid = text();
@override
final TextBlocks textBlocks = TextBlocks();

@override
void initState() {
super.initState();
Expand Down Expand Up @@ -104,7 +104,7 @@ class ChatPageState extends State<ChatPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
children: tWid.chatlog(
children: textBlocks.chatlog(
conversation: [
{
"user": "User",
Expand Down Expand Up @@ -136,7 +136,7 @@ class ChatPageState extends State<ChatPage> {
lastUser: ""
),
),
text.infoShort(
TextBlocks.infoShort(
title: engine.dict.value("welcome"),
context: context,
subtitle: "",
Expand All @@ -146,7 +146,7 @@ class ChatPageState extends State<ChatPage> {
)
: Column(
children: [
...tWid.chatlog(
...textBlocks.chatlog(
conversation: engine.context,
context: context,
aiChunk: engine.responseText,
Expand Down
4 changes: 2 additions & 2 deletions lib/pages/chats.dart
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ class ChatsPageState extends State<ChatsPage> {
}).toList().whereNot((crd) => crd == null).cast<Widget>(),
]
),
text.info(
TextBlocks.info(
title: engine.isLoading?engine.dict.value("still_generating"):engine.dict.value(engine.chats.isEmpty?"no_chats":"chats_desc").replaceAll("%chatnum%", engine.chats.length.toString()),
subtitle: engine.chats.isEmpty?engine.dict.value("new_chat"):"",
action: engine.chats.isNotEmpty?(){}:engine.isLoading?(){}:(){
Expand Down Expand Up @@ -303,4 +303,4 @@ class ChatsPageState extends State<ChatsPage> {
)
);
}
}
}
12 changes: 7 additions & 5 deletions lib/pages/intro.dart
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ class IntroPageState extends State<IntroPage> {
]),
if(engine.modelDownloadLog.isNotEmpty)
if(engine.modelDownloadLog[engine.modelDownloadLog.length-1]["info"] == "downloading_model")
text.infoShort(
TextBlocks.infoShort(
title: engine.dict.value("welcome_gtfo"),
subtitle: "",
action: () {},
Expand Down Expand Up @@ -257,9 +257,11 @@ class IntroPageState extends State<IntroPage> {
title: language["origin"],
subtitle: language["name"] == language["origin"] ? "" : language["name"],
action: () async {
final navigator = Navigator.of(dialogContext);
await engine.dict.saveLanguage(language["id"]);
if (!mounted) return;
setState(() {});
Navigator.of(dialogContext).pop();
navigator.pop();
}
);
}).toList().cast<Widget>()
Expand Down Expand Up @@ -303,7 +305,7 @@ class IntroPageState extends State<IntroPage> {
SizedBox(height: 20,),
if(engine.modelDownloadLog.isNotEmpty)
if(engine.modelDownloadLog[engine.modelDownloadLog.length-1]["status"] == "Download")
text.info(
TextBlocks.info(
title: engine.dict.value("welcome_download").replaceAll("%size%", convertSize(engine.usualModelSize, false)),
subtitle: "",
action: () {},
Expand All @@ -312,7 +314,7 @@ class IntroPageState extends State<IntroPage> {

if(engine.modelDownloadLog.isNotEmpty)
if(!(engine.modelDownloadLog[engine.modelDownloadLog.length-1]["status"] == "Download"))
text.info(
TextBlocks.info(
title: engine.modelInfo["version"] == null
? engine.dict.value("welcome_unavailable")
: engine.modelInfo["version"] == "Unknown"
Expand Down Expand Up @@ -343,4 +345,4 @@ class IntroPageState extends State<IntroPage> {
);
});
}
}
}
Loading