Flutter抄袭检测插件plagiarism_checker_plus的使用

Flutter抄袭检测插件plagiarism_checker_plus的使用

plagiarism_checker_plus 是一个用于检测文本相似度和潜在抄袭的 Flutter 包。该包提供了多种算法选择(如余弦相似性和杰卡德相似性)、可定制的相似度阈值以及详细的分析结果。

特性

  • 🔍 多种算法:可以选择余弦相似性、杰卡德相似性或同时使用两者。
  • 🎛️ 可定制阈值:设置自己的相似度阈值来确定抄袭。
  • 📊 详细分析:获得全面的相似度分数和结果。
  • 🚀 简单集成:简单的 API 实现快速集成。
  • 高效性能:优化处理小到大的文本比较。

安装

pubspec.yaml 文件中添加 plagiarism_checker_plus

dependencies:
  plagiarism_checker_plus: ^1.0.3

然后运行以下命令安装包:

flutter pub get

使用

基本示例

import 'package:plagiarism_checker_plus/plagiarism_checker_plus.dart';

void main() {
  final checker = PlagiarismCheckerPlus(
    algorithm: Algorithm.both, // 同时使用余弦和杰卡德相似性
    threshold: 0.5, // 默认相似度阈值
  );

  final text1 = "这是用于测试相似性的样本文本。";
  final text2 = "这是另一段用于相似性测试的样本文本。";

  final result = checker.check(text1, text2);
  print("相似度得分: ${result.similarityScore}");
  print("使用的算法: ${result.algorithm}");
  print("是否为抄袭: ${result.isPlagiarized}");
}

算法选择

使用余弦相似性
final checker = PlagiarismCheckerPlus(
  algorithm: Algorithm.cosine,
  threshold: 0.5,
);
使用杰卡德相似性
final checker = PlagiarismCheckerPlus(
  algorithm: Algorithm.jaccard,
  threshold: 0.4,
);
使用两种算法
final checker = PlagiarismCheckerPlus(
  algorithm: Algorithm.both,
  threshold: 0.5,
);

API 参考

PlagiarismCheckerPlus

初始化检查器所需的类,并设置所需参数。

参数
  • algorithm: 要使用的算法 (Algorithm.cosine, Algorithm.jaccard, 或 Algorithm.both)
  • threshold: 相似度分数阈值(0.0 到 1.0)以确定抄袭

PlagiarismResult

check 函数返回的结果对象。

属性
  • similarityScore: 两段文本之间的相似度得分(0.0 到 1.0)
  • algorithm: 计算中使用的算法
  • isPlagiarized: 表示相似度是否达到/超过阈值的布尔值

如何工作

余弦相似性

  • 将文本转换为向量
  • 计算向量之间的余弦角度
  • 适用于捕捉语义相似性

杰卡德相似性

  • 基于单词交集/并集测量相似性
  • 适用于直接词重叠比较
  • 对不同长度的文本表现良好

限制

  • 目前仅针对英语和拉丁字母语言进行优化
  • 相似度分数可能因文本复杂度而异
  • 大型文本可能需要额外的处理时间

未来计划

  • 支持更多相似性算法
  • 增强多语言支持
  • 生成详细的匹配报告,并突出显示相似部分
  • 优化大型文本的性能

贡献

欢迎贡献!请参阅我们的贡献指南了解详情。

许可证

此包在 MIT 许可证下可用。有关更多细节,请参阅LICENSE文件。

支持

对于错误报告和功能请求,请在 GitHub 上创建一个issue

示例应用

查看 example 目录下的完整示例应用:

cd example
flutter run

额外资源

示例代码

以下是完整的示例代码:

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '抄袭检测增强版',
      theme: ThemeData(
        useMaterial3: true,
        colorScheme: ColorScheme.fromSeed(
          seedColor: const Color(0xFF6750A4),
          brightness: Brightness.light,
        ),
      ),
      home: const MyHomePage(),
    );
  }
}

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

  [@override](/user/override)
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final checker = PlagiarismCheckerPlus();
  final TextEditingController text1Controller = TextEditingController();
  final TextEditingController text2Controller = TextEditingController();
  double threshold = 0.7;
  Algorithm selectedAlgorithm = Algorithm.average;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          '抄袭检测增强版',
          style: TextStyle(fontWeight: FontWeight.w600),
        ),
        elevation: 0,
        centerTitle: true,
      ),
      body: Container(
        width: MediaQuery.sizeOf(context).width,
        height: MediaQuery.sizeOf(context).height,
        decoration: BoxDecoration(
          gradient: LinearGradient(
            begin: Alignment.topCenter,
            end: Alignment.bottomCenter,
            colors: [
              Theme.of(context).colorScheme.surface,
              Theme.of(context).colorScheme.surface.withOpacity(0.8),
            ],
          ),
        ),
        child: Column(
          children: [
            Expanded(
              flex: 4,
              child: Column(
                children: [
                  Expanded(
                    child: Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          _buildSectionTitle('原文本'),
                          const SizedBox(height: 8),
                          Expanded(
                            child: _buildTextArea(
                              text1Controller,
                              '在此处输入或粘贴原文本...',
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                  Expanded(
                    child: Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          _buildSectionTitle('对比文本'),
                          const SizedBox(height: 8),
                          Expanded(
                            child: _buildTextArea(
                              text2Controller,
                              '在此处输入或粘贴要对比的文本...',
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ],
              ),
            ),
            Expanded(
              flex: 2,
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: Column(
                  children: [
                    _buildSettingsSection(),
                    const SizedBox(height: 16),
                    ElevatedButton.icon(
                      onPressed: _checkPlagiarism,
                      style: ElevatedButton.styleFrom(
                        padding: const EdgeInsets.symmetric(
                          horizontal: 32,
                          vertical: 16,
                        ),
                        shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(30),
                          side: BorderSide(
                            color: Theme.of(context).colorScheme.primary,
                          ),
                        ),
                      ),
                      icon: const Icon(Icons.compare_arrows),
                      label: const Text('分析相似度'),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildSectionTitle(String title) {
    return Text(
      title,
      style: TextStyle(
        fontSize: 16,
        fontWeight: FontWeight.w600,
        color: Theme.of(context).colorScheme.primary,
      ),
    );
  }

  Widget _buildTextArea(TextEditingController controller, String hint) {
    return Container(
      decoration: BoxDecoration(
        color: Theme.of(context).colorScheme.surface,
        borderRadius: BorderRadius.circular(12),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withOpacity(0.05),
            blurRadius: 10,
            offset: const Offset(0, 2),
          ),
        ],
      ),
      child: TextField(
        controller: controller,
        decoration: InputDecoration(
          hintText: hint,
          hintStyle: TextStyle(color: Colors.grey.shade400),
          border: OutlineInputBorder(
            borderRadius: BorderRadius.circular(12),
            borderSide: BorderSide.none,
          ),
          filled: true,
          fillColor: Colors.white,
          contentPadding: const EdgeInsets.all(16),
        ),
        maxLines: null,
        expands: true,
        textAlignVertical: TextAlignVertical.top,
        style: const TextStyle(fontSize: 14),
      ),
    );
  }

  Widget _buildSettingsSection() {
    return Container(
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: Theme.of(context).colorScheme.surface,
        borderRadius: BorderRadius.circular(12),
        border: Border.all(
          color: Theme.of(context).colorScheme.outline.withOpacity(0.1),
        ),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const Text(
            '分析设置',
            style: TextStyle(
              fontSize: 14,
              fontWeight: FontWeight.w600,
            ),
          ),
          const SizedBox(height: 8),
          Row(
            children: [
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      '算法',
                      style: TextStyle(
                        fontSize: 12,
                        color: Colors.grey.shade600,
                      ),
                    ),
                    const SizedBox(height: 4),
                    DropdownButtonFormField<Algorithm>(
                      value: selectedAlgorithm,
                      decoration: InputDecoration(
                        contentPadding: const EdgeInsets.symmetric(
                          horizontal: 12,
                          vertical: 4,
                        ),
                        border: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(8),
                          borderSide: BorderSide(
                            color: Theme.of(context).colorScheme.outline,
                          ),
                        ),
                      ),
                      onChanged: (Algorithm? newValue) {
                        setState(() {
                          selectedAlgorithm = newValue!;
                        });
                      },
                      items: Algorithm.values.map((Algorithm algorithm) {
                        return DropdownMenuItem<Algorithm>(
                          value: algorithm,
                          child: Text(
                            algorithm.toString().split('.').last,
                            style: const TextStyle(fontSize: 12),
                          ),
                        );
                      }).toList(),
                    ),
                  ],
                ),
              ),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      '阈值: ${threshold.toStringAsFixed(1)}',
                      style: TextStyle(
                        fontSize: 12,
                        color: Colors.grey.shade600,
                      ),
                    ),
                    Slider(
                      value: threshold,
                      min: 0.0,
                      max: 1.0,
                      divisions: 10,
                      label: threshold.toStringAsFixed(1),
                      onChanged: (double value) {
                        setState(() {
                          threshold = value;
                        });
                      },
                    ),
                  ],
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }

  void _checkPlagiarism() {
    final text1 = text1Controller.text;
    final text2 = text2Controller.text;

    if (text1.isEmpty || text2.isEmpty) {
      _showDialog(
        '需要输入',
        '请输入两段文本以进行比较。',
        isError: true,
      );
      return;
    }

    final result = checker.check(
      text1,
      text2,
      algorithm: selectedAlgorithm,
      threshold: threshold,
    );

    _showResultDialog(result);
  }

  void _showDialog(String title, String content, {bool isError = false}) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(16),
          ),
          title: Text(
            title,
            style: const TextStyle(fontWeight: FontWeight.w600),
          ),
          content: Text(
            content,
            style: const TextStyle(),
          ),
          actions: [
            TextButton(
              child: Text(
                '确定',
                style: TextStyle(
                  color: isError
                      ? Theme.of(context).colorScheme.error
                      : Theme.of(context).colorScheme.primary,
                ),
              ),
              onPressed: () => Navigator.of(context).pop(),
            ),
          ],
        );
      },
    );
  }

  void _showResultDialog(PlagiarismResult result) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(16),
          ),
          title: const Text(
            '分析结果',
            style: TextStyle(fontWeight: FontWeight.w600),
          ),
          content: Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              _buildResultItem(
                '相似度得分',
                '${(result.similarityScore * 100).toStringAsFixed(1)}%',
                result.similarityScore > threshold ? Colors.red : Colors.green,
              ),
              const SizedBox(height: 16),
              _buildResultItem(
                '使用的算法',
                result.algorithm.toString().split('.').last,
                Theme.of(context).colorScheme.primary,
              ),
              const SizedBox(height: 16),
              _buildResultItem(
                '状态',
                result.isPlagiarized
                    ? '疑似抄袭'
                    : '原创内容',
                result.isPlagiarized ? Colors.red : Colors.green,
              ),
            ],
          ),
          actions: [
            TextButton(
              child: Text(
                '关闭',
                style: TextStyle(
                  color: Theme.of(context).colorScheme.primary,
                ),
              ),
              onPressed: () => Navigator.of(context).pop(),
            ),
          ],
        );
      },
    );
  }

  Widget _buildResultItem(String label, String value, Color valueColor) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          label,
          style: TextStyle(
            fontSize: 14,
            color: Colors.grey.shade600,
          ),
        ),
        const SizedBox(height: 4),
        Text(
          value,
          style: TextStyle(
            fontSize: 16,
            fontWeight: FontWeight.w600,
            color: valueColor,
          ),
        ),
      ],
    );
  }
}

更多关于Flutter抄袭检测插件plagiarism_checker_plus的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter抄袭检测插件plagiarism_checker_plus的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用plagiarism_checker_plus插件的一个示例代码案例。这个插件主要用于检测文本的抄袭情况,通常会调用一个外部的抄袭检测API。需要注意的是,具体API的使用可能会涉及到API密钥和其他配置,因此在实际项目中需要根据具体API文档进行调整。

首先,确保你已经在pubspec.yaml文件中添加了plagiarism_checker_plus依赖:

dependencies:
  flutter:
    sdk: flutter
  plagiarism_checker_plus: ^最新版本号  # 请替换为实际的最新版本号

然后,运行flutter pub get来安装依赖。

接下来,在你的Flutter项目中,你可以按照以下步骤使用plagiarism_checker_plus插件:

  1. 导入插件
import 'package:plagiarism_checker_plus/plagiarism_checker_plus.dart';
  1. 配置API密钥(如果插件或API需要):

某些抄袭检测服务可能需要API密钥。如果plagiarism_checker_plus插件需要API密钥进行配置,你可能需要在初始化时提供它。这通常会在插件的文档中说明。这里假设你需要设置一个API密钥:

void configurePlagiarismChecker() {
  // 假设插件提供了一个配置方法,这里只是示例
  // PlagiarismCheckerPlus.configure(apiKey: '你的API密钥');
  // 注意:上面的代码行是假设的,实际使用时请参考插件文档
}

注意:上面的configure方法是假设的,实际使用时请参考plagiarism_checker_plus的文档了解如何正确配置API密钥。

  1. 检测抄袭

下面是一个简单的示例,展示如何使用插件来检测一段文本的抄袭情况:

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String result = '';

  void checkPlagiarism() async {
    String textToCheck = "这是你要检测的文本内容。";
    try {
      // 假设插件提供了一个checkPlagiarism方法,传入要检测的文本
      var response = await PlagiarismCheckerPlus.checkPlagiarism(text: textToCheck);
      
      // 处理响应数据,这里假设响应是一个包含抄袭信息的对象
      setState(() {
        result = '抄袭率: ${response.plagiarismRate}%\n详细信息: ${response.details}';
      });
    } catch (e) {
      setState(() {
        result = '检测失败: ${e.message}';
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('抄袭检测示例'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              ElevatedButton(
                onPressed: checkPlagiarism,
                child: Text('检测抄袭'),
              ),
              SizedBox(height: 20),
              Text(result),
            ],
          ),
        ),
      ),
    );
  }
}

注意

  • 上面的PlagiarismCheckerPlus.checkPlagiarism方法是假设的,实际使用时请参考plagiarism_checker_plus的文档了解如何正确调用抄袭检测功能。
  • 响应对象response的结构(如plagiarismRatedetails)也是假设的,实际使用时请根据API返回的数据结构进行调整。

在使用任何第三方插件或API时,请务必阅读并遵循其官方文档,以确保正确实现功能并处理可能的错误情况。

回到顶部