audio transcription added

main_production_copilot
WaseemAbbasi22 1 day ago
parent 07ecf3e7bc
commit 27f09e6c4f

@ -3,9 +3,9 @@ class URLs {
static const String appReleaseBuildNumber = "55";
static const host1 = "https://atomsm.hmg.com"; // production url
// static const host1 = "https://atomsm.hmg.com"; // production url
// static const host1 = "https://atomsmdev.hmg.com"; // local DEV url
// static const host1 = "https://atomsmuat.hmg.com"; // local UAT url
static const host1 = "https://atomsmuat.hmg.com"; // local UAT url
static final String _baseUrl = "$_host/mobile"; // host local UAT
// static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis
@ -625,6 +625,7 @@ class URLs {
// Copilot APIs
static get copilotQueryStream => "$_baseUrl/Automation/QueryStream";
static get copilotAudioTranscription => "$_baseUrl/Automation/AudioTranscription";
static get copilotGetQueryHistory => "$_baseUrl/Automation/GetQueryHistory";
static get predictDevice => "$_baseUrl/Automation/PredictDevice";
static copilotGetConversationByThreadId(String threadId) => "$_baseUrl/Automation/GetConversationByThreadId/$threadId";

@ -1,9 +1,12 @@
import 'dart:async';
import 'dart:convert';
import 'dart:developer' as log1;
import 'dart:io';
import 'dart:math';
// import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
@ -15,6 +18,7 @@ class CopilotProvider extends ChangeNotifier {
List<CopilotMessage> messages = [];
bool conversationLoading = false;
bool isStreaming = false;
bool isTranscribing = false;
String? sessionId;
String? errorMessage;
StreamSubscription? _streamSub;
@ -158,6 +162,76 @@ class CopilotProvider extends ChangeNotifier {
}
}
Future<String?> transcribeAudio(File audioFile, String language) async {
isTranscribing = true;
errorMessage = null;
notifyListeners();
log1.log('i am here..');
final exists = await audioFile.exists();
final sizeBytes = exists ? await audioFile.length() : 0;
log1.log(
'[CopilotProvider.transcribeAudio] url=${URLs.copilotAudioTranscription} '
'langId=$language path=${audioFile.path} exists=$exists sizeBytes=$sizeBytes',
);
if (!exists || sizeBytes == 0) {
errorMessage = "Recording file is empty or missing";
isTranscribing = false;
notifyListeners();
return null;
}
try {
final response = await ApiManager.instance.multiPart(
URLs.copilotAudioTranscription,
body: {
"langId": language,
},
showToast: false,
files: [
MultipartFile.fromPath("AudioFile", audioFile.path, filename: audioFile.path.split('/').last),
],
);
log1.log(
'[CopilotProvider.transcribeAudio] statusCode=${response.statusCode} '
'bodyLength=${response.body.length} body=${response.body}',
);
if (response.statusCode < 200 || response.statusCode >= 300) {
errorMessage = "Failed to transcribe audio";
return null;
}
return _extractTranscriptionText(response.body);
} catch (e, st) {
log1.log('[CopilotProvider.transcribeAudio] error=$e\n$st');
errorMessage = "Failed to transcribe audio";
return null;
} finally {
isTranscribing = false;
notifyListeners();
}
}
String? _extractTranscriptionText(String rawBody) {
final trimmedRaw = rawBody.trim();
if (trimmedRaw.isEmpty) return null;
try {
final decoded = jsonDecode(trimmedRaw);
if (decoded is String) {
return decoded.trim();
} else if (decoded is Map) {
final text = decoded['data'] ?? decoded['text'] ?? decoded['result'] ?? decoded['transcription'];
if (text != null) return text.toString().trim();
}
} catch (_) {
// Not JSON, fall back to raw body below.
}
return trimmedRaw;
}
String _generateSessionId() {
final rand = Random();
final bytes = List<int>.generate(16, (_) => rand.nextInt(256));

@ -98,15 +98,26 @@ class _CopilotChatPageState extends State<CopilotChatPage> {
setState(() => _inputState = _InputState.idle);
}
void _sendRecording() async {
Future<void> _sendRecording() async {
if (_recordedFilePath == null) return;
final file = File(_recordedFilePath!);
context.read<CopilotProvider>().sendAudio(file, context.settingProvider.language!);
final language = context.settingProvider.language!;
final provider = context.read<CopilotProvider>();
await _recordedPlayerController.stopPlayer();
_recorderController.reset();
_recordedFilePath = null;
setState(() => _inputState = _InputState.idle);
_scrollToBottom();
final transcribedText = await provider.transcribeAudio(file, language);
if (!mounted) return;
if (transcribedText != null && transcribedText.isNotEmpty) {
_textController.text = transcribedText;
_textController.selection = TextSelection.fromPosition(TextPosition(offset: _textController.text.length));
} else {
(provider.errorMessage ?? "Failed to transcribe audio. Please try again.").showToast;
}
}
@override
@ -237,11 +248,19 @@ class _CopilotChatPageState extends State<CopilotChatPage> {
hintStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: AppColor.lightTextColor(context)),
),
).expanded,
IconButton(
onPressed: _startRecording,
style: const ButtonStyle(tapTargetSize: MaterialTapTargetSize.shrinkWrap),
icon: "chat_mic".toSvgAsset(width: 24, height: 24, color: AppColor.icon2Color(context)),
constraints: const BoxConstraints(),
Consumer<CopilotProvider>(
builder: (_, provider, __) => IconButton(
onPressed: provider.isTranscribing ? null : _startRecording,
style: const ButtonStyle(tapTargetSize: MaterialTapTargetSize.shrinkWrap),
icon: provider.isTranscribing
? const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 2),
)
: "chat_mic".toSvgAsset(width: 24, height: 24, color: AppColor.icon2Color(context)),
constraints: const BoxConstraints(),
),
),
] else if (_inputState == _InputState.recording) ...[
AudioWaveforms(
@ -313,7 +332,7 @@ class _CopilotChatPageState extends State<CopilotChatPage> {
},
style: const ButtonStyle(tapTargetSize: MaterialTapTargetSize.shrinkWrap),
icon: Consumer<CopilotProvider>(
builder: (_, provider, __) => provider.isStreaming
builder: (_, provider, __) => (provider.isStreaming || provider.isTranscribing)
? const SizedBox(
height: 24,
width: 24,

Loading…
Cancel
Save