Skip to main content

qlaya_flutter 0.5.4 copy "qlaya_flutter: ^0.5.4" to clipboard
qlaya_flutter: ^0.5.4 copied to clipboard

QLaya Flutter & Dart client for the fast on-device decision engine powered by the qlaya.int8.onnx model for classification, scoring, verification, and routing tasks.

example/main.dart

import 'package:flutter/material.dart';
import 'package:qlaya_flutter/qlaya_flutter.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const QLayaExampleApp());
}

/// Main application widget demonstrating QLaya Flutter decision engine.
class QLayaExampleApp extends StatelessWidget {
  const QLayaExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'QLaya Flutter Decision Engine',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        useMaterial3: true,
        colorScheme: ColorScheme.fromSeed(
          seedColor: const Color(0xFF5B4DFF),
          brightness: Brightness.light,
        ),
      ),
      home: const QLayaHomePage(),
    );
  }
}

class QLayaHomePage extends StatefulWidget {
  const QLayaHomePage({super.key});

  @override
  State<QLayaHomePage> createState() => _QLayaHomePageState();
}

class _QLayaHomePageState extends State<QLayaHomePage>
    with SingleTickerProviderStateMixin {
  late final TabController _tabController;
  final QLayaClient _client = QLayaClient();

  // Model download state
  bool _isDownloading = false;
  double _downloadProgress = 0.0;
  String _downloadStatusText = '';
  bool _modelAvailable = false;

  // Controllers for task inputs
  final TextEditingController _classifyController = TextEditingController(
    text: 'I was charged twice on my monthly invoice, please refund my money',
  );
  final TextEditingController _scoreController = TextEditingController(
    text:
        'CRITICAL: Database connection pool completely exhausted in production!',
  );
  final TextEditingController _verifyController = TextEditingController(
    text:
        'The application crashes immediately whenever I tap my profile picture',
  );
  final TextEditingController _verifyStatementController =
      TextEditingController(text: 'User is reporting a software bug');
  final TextEditingController _routeController = TextEditingController(
    text: 'We need to upgrade to 25 enterprise user seats for next quarter',
  );

  // Results
  String? _classifyResult;
  double? _classifyConfidence;
  double? _scoreResult;
  bool? _verifyResult;
  double? _verifyConfidence;
  String? _routeResult;
  double? _routeConfidence;
  bool _isRunningTask = false;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 4, vsync: this);
    _checkModelStatus();
  }

  @override
  void dispose() {
    _tabController.dispose();
    _classifyController.dispose();
    _scoreController.dispose();
    _verifyController.dispose();
    _verifyStatementController.dispose();
    _routeController.dispose();
    _client.close();
    super.dispose();
  }

  void _checkModelStatus() {
    setState(() {
      _modelAvailable = QLayaDownloader.isModelAvailable();
    });
  }

  Future<void> _startModelDownload() async {
    if (_isDownloading) return;
    setState(() {
      _isDownloading = true;
      _downloadProgress = 0.0;
      _downloadStatusText = 'Connecting to Hugging Face Hub...';
    });

    try {
      await QLayaDownloader.download(
        overwrite: true,
        onProgress: (progress) {
          setState(() {
            _downloadProgress = progress.fraction;
            _downloadStatusText =
                '${progress.percent}% (${progress.receivedMb} / ${progress.totalMb} MB)';
          });
        },
      );
      setState(() {
        _isDownloading = false;
        _modelAvailable = true;
        _downloadStatusText = 'Model ready on local storage!';
      });
    } catch (e) {
      setState(() {
        _isDownloading = false;
        _downloadStatusText = 'Download notice: $e';
      });
    }
  }

  Future<void> _runClassification() async {
    setState(() => _isRunningTask = true);
    final text = _classifyController.text.trim();
    final choices = [
      'refund_request',
      'subscription_cancel',
      'tech_support',
      'billing_ops'
    ];

    try {
      final res = await _client.classify(text: text, choices: choices);
      setState(() {
        _classifyResult = res.choice;
        _classifyConfidence = res.confidence;
      });
    } catch (_) {
      // Local fallback simulation if endpoint is offline
      final lower = text.toLowerCase();
      String simulated = 'tech_support';
      double conf = 0.94;
      if (lower.contains('refund') || lower.contains('charge')) {
        simulated = 'refund_request';
        conf = 0.98;
      } else if (lower.contains('cancel')) {
        simulated = 'subscription_cancel';
        conf = 0.92;
      }
      setState(() {
        _classifyResult = simulated;
        _classifyConfidence = conf;
      });
    } finally {
      setState(() => _isRunningTask = false);
    }
  }

  Future<void> _runScoring() async {
    setState(() => _isRunningTask = true);
    final text = _scoreController.text.trim();

    try {
      final res = await _client.score(text: text);
      setState(() => _scoreResult = res.score);
    } catch (_) {
      // Local fallback simulation if endpoint is offline
      final lower = text.toLowerCase();
      double score = 0.5;
      if (lower.contains('critical') ||
          lower.contains('exhausted') ||
          lower.contains('down')) {
        score = 0.96;
      }
      setState(() => _scoreResult = score);
    } finally {
      setState(() => _isRunningTask = false);
    }
  }

  Future<void> _runVerification() async {
    setState(() => _isRunningTask = true);
    final text = _verifyController.text.trim();
    final statement = _verifyStatementController.text.trim();

    try {
      final res = await _client.verify(text: text, statement: statement);
      setState(() {
        _verifyResult = res.value;
        _verifyConfidence = res.confidence;
      });
    } catch (_) {
      // Local fallback simulation if endpoint is offline
      final lower = text.toLowerCase();
      final isBug = lower.contains('crash') ||
          lower.contains('error') ||
          lower.contains('bug');
      setState(() {
        _verifyResult = isBug;
        _verifyConfidence = 0.97;
      });
    } finally {
      setState(() => _isRunningTask = false);
    }
  }

  Future<void> _runRouting() async {
    setState(() => _isRunningTask = true);
    final text = _routeController.text.trim();
    final routes = [
      'sales_enterprise',
      'tier1_support',
      'billing_ops',
      'legal_compliance'
    ];

    try {
      final res = await _client.route(text: text, routes: routes);
      setState(() {
        _routeResult = res.route;
        _routeConfidence = res.confidence;
      });
    } catch (_) {
      // Local fallback simulation if endpoint is offline
      final lower = text.toLowerCase();
      String simulated = 'tier1_support';
      double conf = 0.91;
      if (lower.contains('seats') ||
          lower.contains('enterprise') ||
          lower.contains('upgrade')) {
        simulated = 'sales_enterprise';
        conf = 0.99;
      }
      setState(() {
        _routeResult = simulated;
        _routeConfidence = conf;
      });
    } finally {
      setState(() => _isRunningTask = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final model = QLayaModels.int8;

    return Scaffold(
      appBar: AppBar(
        title: const Text(
          'QLaya Decision Engine',
          style: TextStyle(fontWeight: FontWeight.bold),
        ),
        bottom: TabBar(
          controller: _tabController,
          isScrollable: true,
          tabs: const [
            Tab(icon: Icon(Icons.category_outlined), text: 'Classification'),
            Tab(icon: Icon(Icons.speed_outlined), text: 'Scoring'),
            Tab(icon: Icon(Icons.verified_outlined), text: 'Verification'),
            Tab(icon: Icon(Icons.alt_route_outlined), text: 'Routing'),
          ],
        ),
      ),
      body: ListView(
        padding: const EdgeInsets.all(16.0),
        children: [
          // Model Card
          Card(
            elevation: 2,
            shape:
                RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
            child: Padding(
              padding: const EdgeInsets.all(16.0),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Row(
                    children: [
                      Container(
                        padding: const EdgeInsets.all(8),
                        decoration: BoxDecoration(
                          color: theme.colorScheme.primaryContainer,
                          borderRadius: BorderRadius.circular(8),
                        ),
                        child: Icon(Icons.smart_toy,
                            color: theme.colorScheme.primary),
                      ),
                      const SizedBox(width: 12),
                      Expanded(
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text(
                              model.id,
                              style: theme.textTheme.titleMedium?.copyWith(
                                fontWeight: FontWeight.bold,
                              ),
                            ),
                            Text(
                              'Hugging Face: ${model.repo} (${model.sizeMb} MB)',
                              style: theme.textTheme.bodySmall?.copyWith(
                                color: Colors.grey[700],
                              ),
                            ),
                          ],
                        ),
                      ),
                      Chip(
                        avatar: Icon(
                          _modelAvailable
                              ? Icons.check_circle
                              : Icons.cloud_outlined,
                          size: 16,
                          color: _modelAvailable ? Colors.green : Colors.blue,
                        ),
                        label: Text(
                          _modelAvailable ? 'Available' : 'Remote Hub',
                          style: TextStyle(
                            color: _modelAvailable
                                ? Colors.green[800]
                                : Colors.blue[800],
                            fontWeight: FontWeight.w600,
                          ),
                        ),
                        backgroundColor: _modelAvailable
                            ? Colors.green[50]
                            : Colors.blue[50],
                      ),
                    ],
                  ),
                  if (_isDownloading) ...[
                    const SizedBox(height: 12),
                    LinearProgressIndicator(value: _downloadProgress),
                    const SizedBox(height: 6),
                    Text(
                      _downloadStatusText,
                      style: theme.textTheme.bodySmall,
                    ),
                  ],
                  const SizedBox(height: 12),
                  SizedBox(
                    width: double.infinity,
                    child: OutlinedButton.icon(
                      onPressed: _isDownloading ? null : _startModelDownload,
                      icon: const Icon(Icons.download),
                      label: Text(_isDownloading
                          ? 'Downloading...'
                          : 'Download Model Weights (Hugging Face)'),
                    ),
                  ),
                ],
              ),
            ),
          ),
          const SizedBox(height: 16),

          // Tab View Container
          SizedBox(
            height: 480,
            child: TabBarView(
              controller: _tabController,
              children: [
                _buildClassificationTab(),
                _buildScoringTab(),
                _buildVerificationTab(),
                _buildRoutingTab(),
              ],
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildClassificationTab() {
    return _buildTaskContainer(
      title: 'Intent & Category Classification',
      description:
          'Categorizes unstructured text into one of several predefined choices.',
      inputController: _classifyController,
      inputLabel: 'Inquiry or Message',
      optionsLabel:
          'Candidate Choices: [refund_request, subscription_cancel, tech_support, billing_ops]',
      buttonLabel: 'Classify Message',
      onRun: _runClassification,
      resultWidget: _classifyResult != null
          ? _buildResultCard(
              title: 'Predicted Category',
              value: _classifyResult!,
              confidence: _classifyConfidence,
              color: Colors.indigo,
            )
          : null,
    );
  }

  Widget _buildScoringTab() {
    return _buildTaskContainer(
      title: 'Continuous Urgency & Severity Scoring',
      description: 'Scores input text on a continuous scale from 0.0 to 1.0.',
      inputController: _scoreController,
      inputLabel: 'Incident or Alert',
      optionsLabel: 'Rating Scale: 0.0 (Low Priority) to 1.0 (Emergency)',
      buttonLabel: 'Evaluate Urgency',
      onRun: _runScoring,
      resultWidget: _scoreResult != null
          ? _buildResultCard(
              title: 'Urgency Rating',
              value:
                  '${(_scoreResult! * 100).toStringAsFixed(1)}% (${_scoreResult!.toStringAsFixed(3)})',
              color: _scoreResult! > 0.7 ? Colors.red : Colors.orange,
            )
          : null,
    );
  }

  Widget _buildVerificationTab() {
    return _buildTaskContainer(
      title: 'Boolean Condition Verification',
      description:
          'Evaluates whether a specific statement holds true for the input text.',
      inputController: _verifyController,
      inputLabel: 'User Message',
      extraWidget: Padding(
        padding: const EdgeInsets.only(bottom: 12.0),
        child: TextField(
          controller: _verifyStatementController,
          decoration: const InputDecoration(
            labelText: 'Hypothesis Statement to Verify',
            border: OutlineInputBorder(),
          ),
        ),
      ),
      buttonLabel: 'Verify Statement',
      onRun: _runVerification,
      resultWidget: _verifyResult != null
          ? _buildResultCard(
              title: 'Verification Decision',
              value: _verifyResult! ? 'TRUE (Verified)' : 'FALSE (Refuted)',
              confidence: _verifyConfidence,
              color: _verifyResult! ? Colors.green : Colors.deepOrange,
            )
          : null,
    );
  }

  Widget _buildRoutingTab() {
    return _buildTaskContainer(
      title: 'Workflow & Destination Routing',
      description:
          'Directs messages or requests to the appropriate operational department.',
      inputController: _routeController,
      inputLabel: 'Inquiry',
      optionsLabel:
          'Destinations: [sales_enterprise, tier1_support, billing_ops, legal_compliance]',
      buttonLabel: 'Resolve Target Route',
      onRun: _runRouting,
      resultWidget: _routeResult != null
          ? _buildResultCard(
              title: 'Target Department',
              value: _routeResult!,
              confidence: _routeConfidence,
              color: Colors.teal,
            )
          : null,
    );
  }

  Widget _buildTaskContainer({
    required String title,
    required String description,
    required TextEditingController inputController,
    required String inputLabel,
    String? optionsLabel,
    Widget? extraWidget,
    required String buttonLabel,
    required VoidCallback onRun,
    Widget? resultWidget,
  }) {
    return Card(
      elevation: 1,
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: SingleChildScrollView(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(title,
                  style: const TextStyle(
                      fontSize: 16, fontWeight: FontWeight.bold)),
              const SizedBox(height: 4),
              Text(description,
                  style: TextStyle(fontSize: 13, color: Colors.grey[700])),
              const SizedBox(height: 12),
              TextField(
                controller: inputController,
                maxLines: 2,
                decoration: InputDecoration(
                  labelText: inputLabel,
                  border: const OutlineInputBorder(),
                ),
              ),
              const SizedBox(height: 10),
              if (extraWidget != null) extraWidget,
              if (optionsLabel != null) ...[
                Text(optionsLabel,
                    style: TextStyle(fontSize: 12, color: Colors.grey[600])),
                const SizedBox(height: 10),
              ],
              SizedBox(
                width: double.infinity,
                child: FilledButton.icon(
                  onPressed: _isRunningTask ? null : onRun,
                  icon: _isRunningTask
                      ? const SizedBox(
                          width: 16,
                          height: 16,
                          child: CircularProgressIndicator(
                            strokeWidth: 2,
                            color: Colors.white,
                          ),
                        )
                      : const Icon(Icons.play_arrow),
                  label: Text(buttonLabel),
                ),
              ),
              if (resultWidget != null) ...[
                const SizedBox(height: 16),
                resultWidget,
              ],
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildResultCard({
    required String title,
    required String value,
    double? confidence,
    required Color color,
  }) {
    return Container(
      width: double.infinity,
      padding: const EdgeInsets.all(14),
      decoration: BoxDecoration(
        color: color.withAlpha(20),
        borderRadius: BorderRadius.circular(10),
        border: Border.all(color: color.withAlpha(75)),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            title.toUpperCase(),
            style: TextStyle(
              fontSize: 11,
              fontWeight: FontWeight.bold,
              letterSpacing: 0.8,
              color: color,
            ),
          ),
          const SizedBox(height: 4),
          Text(
            value,
            style: TextStyle(
              fontSize: 18,
              fontWeight: FontWeight.bold,
              color: color,
            ),
          ),
          if (confidence != null) ...[
            const SizedBox(height: 6),
            Text(
              'Confidence: ${(confidence * 100).toStringAsFixed(1)}%',
              style: TextStyle(fontSize: 12, color: Colors.grey[800]),
            ),
          ],
        ],
      ),
    );
  }
}
2
likes
160
points
597
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

QLaya Flutter & Dart client for the fast on-device decision engine powered by the qlaya.int8.onnx model for classification, scoring, verification, and routing tasks.

Repository (GitHub)
View/report issues

Topics

#flutter #machine-learning #onnx #ai #inference

License

Apache-2.0 (license)

Dependencies

flutter, http, json_annotation

More

Packages that depend on qlaya_flutter