feat: enforce iOS AI safety policy and citations
This commit is contained in:
@@ -26,10 +26,6 @@
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSBluetoothAlwaysUsageDescription</key>
|
||||
<string>需要使用蓝牙连接支持的血压计等健康设备,以同步用户主动测量的健康数据</string>
|
||||
<key>NSBluetoothPeripheralUsageDescription</key>
|
||||
<string>需要使用蓝牙连接支持的血压计等健康设备</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>需要使用相机拍摄饮食照片和体检报告,以便 AI 分析和记录</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
|
||||
@@ -9,9 +9,22 @@ const String baseUrl = String.fromEnvironment(
|
||||
'API_BASE_URL',
|
||||
defaultValue: kReleaseMode
|
||||
? 'https://erpapi.datalumina.cn/xiaomai'
|
||||
: 'http://10.4.225.209:5000',
|
||||
: 'http://10.4.232.91:5000',
|
||||
);
|
||||
|
||||
const String _configuredAppPolicy = String.fromEnvironment(
|
||||
'APP_POLICY_PROFILE',
|
||||
defaultValue: '',
|
||||
);
|
||||
|
||||
String get appPolicyProfile {
|
||||
if (_configuredAppPolicy == 'android-standard' ||
|
||||
_configuredAppPolicy == 'ios-medical-citations') {
|
||||
return _configuredAppPolicy;
|
||||
}
|
||||
return Platform.isIOS ? 'ios-medical-citations' : 'android-standard';
|
||||
}
|
||||
|
||||
class ApiException implements Exception {
|
||||
final int? code;
|
||||
final String message;
|
||||
@@ -56,7 +69,10 @@ class ApiClient {
|
||||
baseUrl: baseUrl,
|
||||
connectTimeout: const Duration(seconds: 15),
|
||||
receiveTimeout: const Duration(seconds: 60),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-App-Policy': appPolicyProfile,
|
||||
},
|
||||
),
|
||||
) {
|
||||
_dio.interceptors.add(_AuthInterceptor(this));
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'navigation_provider.dart';
|
||||
@@ -120,9 +122,9 @@ Widget buildPage(RouteInfo route, WidgetRef ref) {
|
||||
case 'doctorFollowUpEdit':
|
||||
return DoctorFollowUpEditPage(id: params['id']);
|
||||
case 'devices':
|
||||
return const DeviceManagementPage();
|
||||
return Platform.isIOS ? const HomePage() : const DeviceManagementPage();
|
||||
case 'deviceScan':
|
||||
return const DeviceScanPage();
|
||||
return Platform.isIOS ? const HomePage() : const DeviceScanPage();
|
||||
case 'healthArchive':
|
||||
return const HealthArchivePage();
|
||||
case 'followups':
|
||||
|
||||
@@ -1296,7 +1296,7 @@ class ChatMessagesView extends ConsumerWidget {
|
||||
pushRoute(ref, 'reports');
|
||||
break;
|
||||
case 'device':
|
||||
pushRoute(ref, 'devices');
|
||||
if (!Platform.isIOS) pushRoute(ref, 'devices');
|
||||
break;
|
||||
default:
|
||||
if (uri.host.isNotEmpty) pushRoute(ref, uri.host);
|
||||
@@ -2199,12 +2199,13 @@ final _agentActions = <ActiveAgent, List<_AgentAction>>{
|
||||
isWide: true,
|
||||
route: 'trend',
|
||||
),
|
||||
_AgentAction(
|
||||
label: '蓝牙录入',
|
||||
icon: Icons.bluetooth,
|
||||
isWide: true,
|
||||
route: 'devices',
|
||||
),
|
||||
if (!Platform.isIOS)
|
||||
_AgentAction(
|
||||
label: '蓝牙录入',
|
||||
icon: Icons.bluetooth,
|
||||
isWide: true,
|
||||
route: 'devices',
|
||||
),
|
||||
],
|
||||
ActiveAgent.diet: [
|
||||
_AgentAction(
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
@@ -49,11 +51,12 @@ class SettingsPage extends ConsumerWidget {
|
||||
title: '长辈模式',
|
||||
onTap: () => pushRoute(ref, 'elderMode'),
|
||||
),
|
||||
_SettingsTile(
|
||||
icon: LucideIcons.bluetooth,
|
||||
title: '蓝牙设备',
|
||||
onTap: () => pushRoute(ref, 'devices'),
|
||||
),
|
||||
if (!Platform.isIOS)
|
||||
_SettingsTile(
|
||||
icon: LucideIcons.bluetooth,
|
||||
title: '蓝牙设备',
|
||||
onTap: () => pushRoute(ref, 'devices'),
|
||||
),
|
||||
_SettingsTile(
|
||||
icon: LucideIcons.bell,
|
||||
title: '消息通知',
|
||||
|
||||
@@ -63,7 +63,10 @@ class SseHandler {
|
||||
cancelToken: cancelToken,
|
||||
options: Options(
|
||||
responseType: ResponseType.stream,
|
||||
headers: {'Authorization': 'Bearer $token'},
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'X-App-Policy': appPolicyProfile,
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
@@ -431,12 +433,13 @@ class _NavigationSection extends StatelessWidget {
|
||||
route: 'exercisePlan',
|
||||
colors: AppColors.exerciseGradient.colors,
|
||||
),
|
||||
_NavItem(
|
||||
icon: LucideIcons.bluetooth,
|
||||
title: '设备',
|
||||
route: 'devices',
|
||||
colors: AppColors.deviceGradient.colors,
|
||||
),
|
||||
if (!Platform.isIOS)
|
||||
_NavItem(
|
||||
icon: LucideIcons.bluetooth,
|
||||
title: '设备',
|
||||
route: 'devices',
|
||||
colors: AppColors.deviceGradient.colors,
|
||||
),
|
||||
];
|
||||
|
||||
return _LightSection(
|
||||
|
||||
Reference in New Issue
Block a user