init
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -303,3 +303,4 @@ cython_debug/
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
.idea/
|
||||
|
||||
10
.idea/.gitignore
generated
vendored
10
.idea/.gitignore
generated
vendored
@@ -1,10 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Ignored default folder with query files
|
||||
/queries/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
11
.idea/go.imports.xml
generated
11
.idea/go.imports.xml
generated
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GoImports">
|
||||
<option name="excludedPackages">
|
||||
<array>
|
||||
<option value="github.com/pkg/errors" />
|
||||
<option value="golang.org/x/net/context" />
|
||||
</array>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
621
.idea/inspectionProfiles/Project_Default.xml
generated
621
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -1,621 +0,0 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="AddOperatorModifier" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="AddVarianceModifier" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="ArrayInDataClass" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="BintrayPublishingPlugin" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="BooleanLiteralArgument" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="CanBeParameter" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CanBePrimaryConstructorProperty" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CanBeVal" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CanSealedSubClassBeObject" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CascadeIf" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="CdiAlternativeInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CdiDecoratorInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CdiDisposerMethodInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CdiDomBeans" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CdiInjectInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CdiInjectionPointsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CdiInterceptorInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CdiManagedBeanInconsistencyInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CdiNormalScopeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CdiObservesInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CdiScopeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CdiSpecializesInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CdiStereotypeInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CdiStereotypeRestrictionsInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CdiTypedAnnotationInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CdiUnknownProducersForDisposerMethodInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CdiUnproxyableBeanTypesInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="ChangeToMethod" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="ChangeToOperator" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ClashingTraitMethods" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ClassCanBeRecord" enabled="false" level="WEAK WARNING" enabled_by_default="false">
|
||||
<option name="myConversionStrategy" value="SILENTLY" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="ClassName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ComplexRedundantLet" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="ComposeUnknownKeys" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="ComposeUnknownValues" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="ConflictingExtensionProperty" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ConstPropertyName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ConstantConditionIf" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ControlFlowWithEmptyBody" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ConvertCallChainIntoSequence" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="ConvertLambdaToReference" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="ConvertNaNEquality" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ConvertPairConstructorToToFunction" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="ConvertReferenceToLambda" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="ConvertSecondaryConstructorToPrimary" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ConvertToStringTemplate" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="ConvertTryFinallyToUseCall" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ConvertTwoComparisonsToRangeCheck" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="CopyWithoutNamedArguments" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CssBrowserCompatibilityForProperties" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="CssConvertColorToHexInspection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="CssConvertColorToRgbInspection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="CssMissingSemicolon" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="CucumberExamplesColon" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CucumberMissedExamples" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="CucumberTableInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="CucumberUndefinedStep" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="DataClassPrivateConstructor" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="DeferredIsResult" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="DeferredResultUnused" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="DelegatesTo" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="DelegationToVarProperty" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="DeprecatedCallableAddReplaceWith" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="DeprecatedGradleDependency" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="DeprecatedMavenDependency" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="DestructuringWrongName" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="DifferentKotlinGradleVersion" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="DifferentKotlinMavenVersion" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="DifferentMavenStdlibVersion" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="DifferentStdlibGradleVersion" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="DockerFileAddOrCopySemantic" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="DockerFileArgumentCount" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="DockerFileAssignments" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="EmptyRange" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="EmptyWebServiceClass" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="EnumEntryName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="EqualsOrHashCode" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ExplicitThis" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="FakeJvmFieldConstant" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="FoldInitializerAndIfToElvis" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="ForEachParameterNotUsed" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ForgottenDebugOutputInspection" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="configuration">
|
||||
<list>
|
||||
<option value="\Codeception\Util\Debug::debug" />
|
||||
<option value="\Codeception\Util\Debug::pause" />
|
||||
<option value="\Doctrine\Common\Util\Debug::dump" />
|
||||
<option value="\Doctrine\Common\Util\Debug::export" />
|
||||
<option value="\Illuminate\Support\Debug\Dumper::dump" />
|
||||
<option value="\Symfony\Component\Debug\Debug::enable" />
|
||||
<option value="\Symfony\Component\Debug\DebugClassLoader::enable" />
|
||||
<option value="\Symfony\Component\Debug\ErrorHandler::register" />
|
||||
<option value="\Symfony\Component\Debug\ExceptionHandler::register" />
|
||||
<option value="\TYPO3\CMS\Core\Utility\DebugUtility::debug" />
|
||||
<option value="\Zend\Debug\Debug::dump" />
|
||||
<option value="\Zend\Di\Display\Console::export" />
|
||||
<option value="dd" />
|
||||
<option value="debug_print_backtrace" />
|
||||
<option value="debug_zval_dump" />
|
||||
<option value="dpm" />
|
||||
<option value="dpq" />
|
||||
<option value="dsm" />
|
||||
<option value="dump" />
|
||||
<option value="dvm" />
|
||||
<option value="error_log" />
|
||||
<option value="kpr" />
|
||||
<option value="phpinfo" />
|
||||
<option value="print_r" />
|
||||
<option value="var_dump" />
|
||||
<option value="var_export" />
|
||||
<option value="wp_die" />
|
||||
<option value="xdebug_break" />
|
||||
<option value="xdebug_call_class" />
|
||||
<option value="xdebug_call_file" />
|
||||
<option value="xdebug_call_function" />
|
||||
<option value="xdebug_call_line" />
|
||||
<option value="xdebug_code_coverage_started" />
|
||||
<option value="xdebug_debug_zval" />
|
||||
<option value="xdebug_debug_zval_stdout" />
|
||||
<option value="xdebug_dump_superglobals" />
|
||||
<option value="xdebug_enable" />
|
||||
<option value="xdebug_get_code_coverage" />
|
||||
<option value="xdebug_get_collected_errors" />
|
||||
<option value="xdebug_get_declared_vars" />
|
||||
<option value="xdebug_get_function_stack" />
|
||||
<option value="xdebug_get_headers" />
|
||||
<option value="xdebug_get_monitored_functions" />
|
||||
<option value="xdebug_get_profiler_filename" />
|
||||
<option value="xdebug_get_stack_depth" />
|
||||
<option value="xdebug_get_tracefile_name" />
|
||||
<option value="xdebug_is_enabled" />
|
||||
<option value="xdebug_memory_usage" />
|
||||
<option value="xdebug_peak_memory_usage" />
|
||||
<option value="xdebug_print_function_stack" />
|
||||
<option value="xdebug_start_code_coverage" />
|
||||
<option value="xdebug_start_error_collection" />
|
||||
<option value="xdebug_start_function_monitor" />
|
||||
<option value="xdebug_start_trace" />
|
||||
<option value="xdebug_stop_code_coverage" />
|
||||
<option value="xdebug_stop_error_collection" />
|
||||
<option value="xdebug_stop_function_monitor" />
|
||||
<option value="xdebug_stop_trace" />
|
||||
<option value="xdebug_time_index" />
|
||||
<option value="xdebug_var_dump" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="migratedIntoUserSpace" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="FunctionName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="FunctionWithLambdaExpressionBody" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GherkinBrokenTableInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="GherkinMisplacedBackground" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="GherkinScenarioToScenarioOutline" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="GrAnnotationReferencingUnknownIdentifiers" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GrDeprecatedAPIUsage" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GrEqualsBetweenInconvertibleTypes" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GrFinalVariableAccess" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GrMethodMayBeStatic" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GrNamedVariantLabels" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GrPackage" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GrReassignedInClosureLocalVar" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GrUnnecessaryAlias" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GrUnnecessaryDefModifier" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GrUnnecessaryPublicModifier" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GrUnnecessarySemicolon" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GrUnresolvedAccess" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyAccessToStaticFieldLockedOnInstance" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyAccessibility" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyAssignabilityCheck" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyConditionalWithIdenticalBranches" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyConstantConditional" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyConstantIfStatement" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyConstructorNamedArguments" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyDivideByZero" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyDocCheck" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyDoubleNegation" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyDuplicateSwitchBranch" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyEmptyStatementBody" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyFallthrough" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyGStringKey" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyIfStatementWithIdenticalBranches" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyImplicitNullArgumentCall" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyInArgumentCheck" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyInfiniteLoopStatement" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyInfiniteRecursion" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyLabeledStatement" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyMissingReturnStatement" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyPointlessBoolean" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyResultOfObjectAllocationIgnored" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovySillyAssignment" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovySynchronizationOnNonFinalField" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovySynchronizationOnVariableInitializedWithLiteral" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyTrivialConditional" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyTrivialIf" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyUncheckedAssignmentOfMemberOfRawType" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyUnnecessaryContinue" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyUnnecessaryReturn" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyUnreachableStatement" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyUnsynchronizedMethodOverridesSynchronizedMethod" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyUnusedAssignment" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyUnusedCatchParameter" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyUnusedDeclaration" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyUnusedIncOrDec" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="GroovyVariableNotAssigned" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="HasPlatformType" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="HtmlUnknownTag" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="myValues">
|
||||
<value>
|
||||
<list size="16">
|
||||
<item index="0" class="java.lang.String" itemvalue="nobr" />
|
||||
<item index="1" class="java.lang.String" itemvalue="noembed" />
|
||||
<item index="2" class="java.lang.String" itemvalue="comment" />
|
||||
<item index="3" class="java.lang.String" itemvalue="noscript" />
|
||||
<item index="4" class="java.lang.String" itemvalue="embed" />
|
||||
<item index="5" class="java.lang.String" itemvalue="script" />
|
||||
<item index="6" class="java.lang.String" itemvalue="style" />
|
||||
<item index="7" class="java.lang.String" itemvalue="nuxt-img" />
|
||||
<item index="8" class="java.lang.String" itemvalue="nuxt-picture" />
|
||||
<item index="9" class="java.lang.String" itemvalue="nuxt-content" />
|
||||
<item index="10" class="java.lang.String" itemvalue="contentdoc" />
|
||||
<item index="11" class="java.lang.String" itemvalue="contentquery" />
|
||||
<item index="12" class="java.lang.String" itemvalue="nuxt" />
|
||||
<item index="13" class="java.lang.String" itemvalue="ogimagescreenshot" />
|
||||
<item index="14" class="java.lang.String" itemvalue="seokit" />
|
||||
<item index="15" class="java.lang.String" itemvalue="nuxtlink" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
<option name="myCustomValuesEnabled" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="HttpRequestContentLengthIsIgnored" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="HttpRequestPlaceholder" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="IfThenToElvis" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="IfThenToSafeAccess" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="ImplicitNullableNothingType" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ImplicitThis" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="ImplicitlyExposedWebServiceMethods" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="IncorrectHttpHeaderInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="IntroduceWhenSubject" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JBoss" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="JCenterRepository" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JSConstructorReturnsPrimitive" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="JSObsoletePrivateAccessSyntax" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="JSUnresolvedReactComponent" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JavaCollectionsStaticMethod" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JavaCollectionsStaticMethodOnImmutableList" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JavaFxColorRgb" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JavaFxDefaultTag" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JavaFxEventHandler" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JavaFxRedundantPropertyValue" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JavaFxResourcePropertyValue" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JavaFxUnresolvedFxIdReference" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JavaFxUnresolvedStyleClassReference" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JavaFxUnusedImports" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JavaMapForEach" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JavaStylePropertiesInvocation" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="JoinDeclarationAndAssignment" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JpaAttributeMemberSignatureInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="JpaAttributeTypeInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="JpaConfigDomFacetInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JpaDataSourceORMDomInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="JpaDataSourceORMInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="JpaDomInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="JpaEntityListenerInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="JpaEntityListenerWarningsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JpaMissingIdInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="JpaModelReferenceInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="JpaORMDomInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="JpaObjectClassSignatureInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="JpaQlInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="JpaQueryApiInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="KDocUnresolvedReference" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="KotlinCovariantEquals" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="KotlinDeprecation" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="KotlinDoubleNegation" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="KotlinEqualsBetweenInconvertibleTypes" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="KotlinInternalInJava" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="KotlinInvalidBundleOrProperty" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="KotlinMavenPluginPhase" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="KotlinRedundantOverride" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="KotlinSealedInheritorsInJava" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="KotlinTestJUnit" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="KotlinThrowableNotThrown" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="KotlinUnusedImport" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="LSPLocalInspectionTool" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="LateinitVarOverridesLateinitVar" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="LeakingThis" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="LessResolvedByNameOnly" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="LessUnresolvedMixin" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="LessUnresolvedVariable" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="LiftReturnOrAssignment" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="LocalVariableName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="LoopToCallChain" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="MainFunctionReturnUnit" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="MapGetWithNotNullAssertionOperator" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="MayBeConstant" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="MemberVisibilityCanBePrivate" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="MicronautDataMethodInconsistencyInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="MicronautDataRepositoryMethodParametersInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="MicronautDataRepositoryMethodReturnTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="MigrateDiagnosticSuppression" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="MissingOverrideAnnotation" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="ignoreObjectMethods" value="true" />
|
||||
<option name="ignoreAnonymousClassMethods" value="false" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="MnProperties" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="MnUnresolvedPathVariable" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="MnYaml" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="MongoJSDeprecationInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="MongoJSResolveInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="MongoJSSideEffectsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="MoveLambdaOutsideParentheses" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="MoveSuspiciousCallableReferenceIntoParentheses" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="MoveVariableDeclarationIntoWhen" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="MsOrderByInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="MultipleMethodDesignatorsInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="MultipleRepositoryUrls" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="MysqlLoadDataPathInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="MysqlParsingInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="NestedLambdaShadowedImplicitParameter" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="NewInstanceOfSingleton" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="NonJaxWsWebServices" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="NullChecksToSafeCall" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="NullableBooleanElvis" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="ObjectLiteralToLambda" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="ObjectPropertyName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ObsoleteExperimentalCoroutines" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="ObsoleteKotlinJsPackages" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="OneWayWebMethod" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="OptionalExpectation" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="OraMissingBodyInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="OraOverloadInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="OraUnmatchedForwardDeclarationInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="OverridingDeprecatedMember" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PackageDirectoryMismatch" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="PackageName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PathAnnotation" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PgSelectFromProcedureInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PlatformExtensionReceiverOfInline" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PrivatePropertyName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PropertyName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ProtectedInFinal" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PyArgumentEqualDefaultInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PyAugmentAssignmentInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PyBehaveInspection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PyClassicStyleClassInspection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PyCompatibilityInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ourVersions">
|
||||
<value>
|
||||
<list size="2">
|
||||
<item index="0" class="java.lang.String" itemvalue="2.7" />
|
||||
<item index="1" class="java.lang.String" itemvalue="3.11" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PyMandatoryEncodingInspection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PyMissingOrEmptyDocstringInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PyMissingTypeHintsInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="RecursiveEqualsCall" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RecursivePropertyAccessor" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantAsSequence" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantAsync" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantCompanionReference" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantElseInIf" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantElvisReturnNull" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantEmptyInitializerBlock" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantEnumConstructorInvocation" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantExplicitType" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantGetter" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantIf" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantLambdaArrow" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantLambdaOrAnonymousFunction" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantModalityModifier" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantNullableReturnType" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantObjectTypeCheck" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantRequireNotNullCall" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantReturnLabel" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantRunCatching" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantSamConstructor" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantSemicolon" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantSetter" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantSuspendModifier" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantUnitExpression" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantUnitReturnType" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantVisibilityModifier" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RedundantWith" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RemoveCurlyBracesFromTemplate" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RemoveEmptyClassBody" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="RemoveEmptyParenthesesFromAnnotationEntry" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RemoveEmptyParenthesesFromLambdaCall" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="RemoveEmptyPrimaryConstructor" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RemoveEmptySecondaryConstructorBody" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RemoveExplicitSuperQualifier" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RemoveExplicitTypeArguments" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RemoveForLoopIndices" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RemoveRedundantBackticks" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RemoveRedundantCallsOfConversionMethods" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RemoveRedundantQualifierName" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RemoveRedundantSpreadOperator" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RemoveSetterParameterType" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RemoveSingleExpressionStringTemplate" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RemoveToStringInStringTemplate" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceArrayEqualityOpWithArraysEquals" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceArrayOfWithLiteral" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceAssertBooleanWithAssertEquality" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceAssociateFunction" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceCallWithBinaryOperator" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceGetOrSet" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceGuardClauseWithFunctionCall" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceIsEmptyWithIfEmpty" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceJavaStaticMethodWithKotlinAnalog" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceManualRangeWithIndicesCalls" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceNegatedIsEmptyWithIsNotEmpty" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplacePutWithAssignment" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceRangeStartEndInclusiveWithFirstLast" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceRangeToWithUntil" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceSizeCheckWithIsNotEmpty" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceSizeZeroCheckWithIsEmpty" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceStringFormatWithLiteral" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceSubstringWithDropLast" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceSubstringWithIndexingOperation" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceSubstringWithSubstringAfter" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceSubstringWithSubstringBefore" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceSubstringWithTake" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceToStringWithStringTemplate" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceToWithInfixForm" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceWithEnumMap" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceWithIgnoreCaseEquals" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ReplaceWithOperatorAssignment" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="RestParamTypeInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="RestResourceMethodInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="RestWrongDefaultValueInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="SafeCastWithReturn" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SassScssResolvedByNameOnly" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SassScssUnresolvedMixin" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SassScssUnresolvedPlaceholderSelector" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SassScssUnresolvedVariable" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ScopeFunctionConversion" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="SecondUnsafeCall" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SecurityAdvisoriesInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="optionConfiguration">
|
||||
<list>
|
||||
<option value="barryvdh/laravel-debugbar" />
|
||||
<option value="behat/behat" />
|
||||
<option value="brianium/paratest" />
|
||||
<option value="codeception/codeception" />
|
||||
<option value="codedungeon/phpunit-result-printer" />
|
||||
<option value="composer/composer" />
|
||||
<option value="doctrine/coding-standard" />
|
||||
<option value="filp/whoops" />
|
||||
<option value="friendsofphp/php-cs-fixer" />
|
||||
<option value="humbug/humbug" />
|
||||
<option value="infection/infection" />
|
||||
<option value="jakub-onderka/php-parallel-lint" />
|
||||
<option value="johnkary/phpunit-speedtrap" />
|
||||
<option value="kalessil/production-dependencies-guard" />
|
||||
<option value="mikey179/vfsStream" />
|
||||
<option value="mockery/mockery" />
|
||||
<option value="mybuilder/phpunit-accelerator" />
|
||||
<option value="orchestra/testbench" />
|
||||
<option value="pdepend/pdepend" />
|
||||
<option value="phan/phan" />
|
||||
<option value="phing/phing" />
|
||||
<option value="phpcompatibility/php-compatibility" />
|
||||
<option value="phpmd/phpmd" />
|
||||
<option value="phpro/grumphp" />
|
||||
<option value="phpspec/phpspec" />
|
||||
<option value="phpspec/prophecy" />
|
||||
<option value="phpstan/phpstan" />
|
||||
<option value="phpunit/phpunit" />
|
||||
<option value="povils/phpmnd" />
|
||||
<option value="roave/security-advisories" />
|
||||
<option value="satooshi/php-coveralls" />
|
||||
<option value="sebastian/phpcpd" />
|
||||
<option value="slevomat/coding-standard" />
|
||||
<option value="spatie/phpunit-watcher" />
|
||||
<option value="squizlabs/php_codesniffer" />
|
||||
<option value="sstalle/php7cc" />
|
||||
<option value="symfony/debug" />
|
||||
<option value="symfony/maker-bundle" />
|
||||
<option value="symfony/phpunit-bridge" />
|
||||
<option value="symfony/var-dumper" />
|
||||
<option value="vimeo/psalm" />
|
||||
<option value="wimg/php-compatibility" />
|
||||
<option value="wp-coding-standards/wpcs" />
|
||||
<option value="yiisoft/yii2-coding-standards" />
|
||||
<option value="yiisoft/yii2-debug" />
|
||||
<option value="yiisoft/yii2-gii" />
|
||||
<option value="zendframework/zend-coding-standard" />
|
||||
<option value="zendframework/zend-debug" />
|
||||
<option value="zendframework/zend-test" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="SelfAssignment" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SelfReferenceConstructorParameter" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SetterBackingFieldAssignment" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SimpleRedundantLet" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SimplifiableCall" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SimplifiableCallChain" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SimplifyAssertNotNull" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="SimplifyBooleanWithConstants" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SimplifyNegatedBinaryExpression" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SimplifyNestedEachInScopeFunction" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SimplifyWhenWithBooleanConstantCondition" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SingletonConstructor" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="SortModifiers" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlAddNotNullColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlAggregatesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlAmbiguousColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlAutoIncrementDuplicateInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlCallNotationInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlCaseVsCoalesceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlCaseVsIfInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlCheckUsingColumnsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlConstantConditionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlCurrentSchemaInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDeprecateTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDerivedTableAliasInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDialectInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDropIndexedColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDtInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDuplicateColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlErrorHandlingInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlIdentifierInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlIdentifierLengthInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlIllegalCursorStateInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlInsertIntoGeneratedColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlInsertNullIntoNotNullInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlInsertValuesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlJoinWithoutOnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlMisleadingReferenceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlMissingReturnInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlMultipleLimitClausesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlNoDataSourceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlNullComparisonInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlRedundantAliasInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlRedundantCodeInCoalesceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlRedundantElseNullInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlRedundantLimitInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlRedundantOrderingDirectionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlResolveInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlShadowingAliasInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlShouldBeInGroupByInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlSideEffectsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlSignatureInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlStorageInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlStringLengthExceededInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlTransactionStatementInTriggerInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlTriggerTransitionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlUnicodeStringLiteralInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlUnreachableCodeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlUnusedCteInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlUnusedSubqueryItemInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlUnusedVariableInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlWithoutWhereInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="Stylelint" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||
<inspection_tool class="SuspendFunctionOnCoroutineScope" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SuspiciousAsDynamic" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SuspiciousCollectionReassignment" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SuspiciousEqualsCombination" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SuspiciousVarProperty" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="TestFunctionName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="TrailingComma" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="TypeCustomizer" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="TypeScriptUnresolvedFunction" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="TypeScriptUnresolvedReactComponent" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="TypeScriptUnresolvedVariable" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="TypeScriptValidateJSTypes" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnlabeledReturnInsideLambda" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="UnnecessaryQualifiedReference" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnnecessaryVariable" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnresolvedReference" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="UnresolvedRestParam" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="UnsafeCastFromDynamic" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="UnstableApiUsage" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="unstableApiAnnotations">
|
||||
<set>
|
||||
<option value="io.reactivex.annotations.Beta" />
|
||||
<option value="io.reactivex.annotations.Experimental" />
|
||||
<option value="org.apache.http.annotation.Beta" />
|
||||
<option value="org.gradle.api.Incubating" />
|
||||
<option value="org.jetbrains.annotations.ApiStatus.Experimental" />
|
||||
<option value="org.jetbrains.annotations.ApiStatus.Internal" />
|
||||
<option value="org.jetbrains.annotations.ApiStatus.ScheduledForRemoval" />
|
||||
<option value="rx.annotations.Beta" />
|
||||
<option value="rx.annotations.Experimental" />
|
||||
</set>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="UnusedDataClassCopyResult" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnusedEquals" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnusedLambdaExpressionBody" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnusedReceiverParameter" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnusedSymbol" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnusedUnaryOperator" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UseExpressionBody" enabled="false" level="INFORMATION" enabled_by_default="false" />
|
||||
<inspection_tool class="UsePropertyAccessSyntax" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UseWithIndex" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="UselessCallOnCollection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UselessCallOnNotNull" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ValidExternallyBoundObject" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="VoidMethodAnnotatedWithGET" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="W3CssValidation" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="myCssVersion" value="css3svg" />
|
||||
<option name="myIgnoreVendorSpecificProperties" value="false" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="WSReferenceInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="WadlDomInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="WebpackConfigHighlighting" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="WrapUnaryOperator" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="WsdlHighlightingInspection" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||
</profile>
|
||||
</component>
|
||||
17
.idea/material_theme_project_new.xml
generated
17
.idea/material_theme_project_new.xml
generated
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MaterialThemeProjectNewConfig">
|
||||
<option name="metadata">
|
||||
<MTProjectMetadataState>
|
||||
<option name="migrated" value="true" />
|
||||
<option name="pristineConfig" value="false" />
|
||||
<option name="userId" value="f935243:19b09dbde27:-7ffe" />
|
||||
</MTProjectMetadataState>
|
||||
</option>
|
||||
<option name="titleBarState">
|
||||
<MTProjectTitleBarConfigState>
|
||||
<option name="overrideColor" value="false" />
|
||||
</MTProjectTitleBarConfigState>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
9
.idea/misc.xml
generated
9
.idea/misc.xml
generated
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ComposerSettings">
|
||||
<execution />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/transcribe.iml" filepath="$PROJECT_DIR$/transcribe.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
20
README.md
20
README.md
@@ -7,6 +7,7 @@ Real-time audio transcription using Whisper AI with optional LLM-powered analysi
|
||||
- Real-time transcription of system audio (Windows/Linux)
|
||||
- Multiple Whisper model sizes (tiny to large)
|
||||
- Multi-language support
|
||||
- **Sentence extraction mode** - Stitches audio chunks into complete sentences
|
||||
- Optional LLM analysis for fact-checking and question generation (via Ollama)
|
||||
- GPU acceleration support
|
||||
- Flexible audio device configuration
|
||||
@@ -17,12 +18,15 @@ Real-time audio transcription using Whisper AI with optional LLM-powered analysi
|
||||
# Install dependencies
|
||||
pip install -r requirements.txt
|
||||
|
||||
# Basic transcription
|
||||
# Basic transcription (no LLM)
|
||||
python transcribe_speakers.py
|
||||
|
||||
# With LLM analysis
|
||||
# With LLM analysis (optional)
|
||||
python transcribe_speakers.py --enable-llm
|
||||
|
||||
# With sentence extraction
|
||||
python transcribe_speakers.py --sentence-mode
|
||||
|
||||
# List audio devices
|
||||
python transcribe_speakers.py --list-devices
|
||||
```
|
||||
@@ -80,9 +84,7 @@ ollama pull llama3.2
|
||||
|
||||
### Available Scripts
|
||||
|
||||
- `transcribe_speakers.py` - Main script with all features
|
||||
- `transcribe_speakers_llm.py` - LLM-enabled version
|
||||
- `transcribe_No_llm.py` - Basic version without LLM support
|
||||
- `transcribe_speakers.py` - Main script with all features (LLM optional via `--enable-llm`)
|
||||
- `transcribe_dual_linux.py` - Linux-specific with dual audio support
|
||||
|
||||
### Common Commands
|
||||
@@ -97,8 +99,11 @@ python transcribe_speakers.py --language es --output transcript.txt
|
||||
# Fast mode (low latency)
|
||||
python transcribe_speakers.py --fast-mode --model tiny --interval 3
|
||||
|
||||
# Maximum accuracy with LLM
|
||||
python transcribe_speakers.py --model large --enable-llm --output enriched.txt
|
||||
# Extract complete sentences from chunks
|
||||
python transcribe_speakers.py --sentence-mode --output sentences.txt
|
||||
|
||||
# Maximum accuracy with LLM and sentence extraction
|
||||
python transcribe_speakers.py --model large --enable-llm --sentence-mode --output enriched.txt
|
||||
|
||||
# Force CPU (avoid GPU issues)
|
||||
python transcribe_speakers.py --force-cpu
|
||||
@@ -119,6 +124,7 @@ python transcribe_speakers.py --force-cpu
|
||||
| `--output` | Save to file | None |
|
||||
| `--force-cpu` | Disable GPU | False |
|
||||
| `--gpu-index` | GPU device index | 0 |
|
||||
| `--sentence-mode` | Extract complete sentences from chunks | False |
|
||||
|
||||
## Model Performance
|
||||
|
||||
|
||||
260
sentence_extractor.py
Normal file
260
sentence_extractor.py
Normal file
@@ -0,0 +1,260 @@
|
||||
"""
|
||||
Sentence extraction from chunked transcriptions.
|
||||
Stitches partial chunks together and extracts complete sentences.
|
||||
"""
|
||||
|
||||
import re
|
||||
from typing import List, Tuple, Optional
|
||||
from collections import deque
|
||||
|
||||
|
||||
class SentenceExtractor:
|
||||
"""
|
||||
Buffers transcription chunks and extracts complete sentences.
|
||||
Handles sentence boundaries that span across audio chunks.
|
||||
"""
|
||||
|
||||
def __init__(self, max_buffer_words=200):
|
||||
"""
|
||||
Initialize the sentence extractor.
|
||||
|
||||
Args:
|
||||
max_buffer_words: Maximum words to keep in buffer before forcing extraction
|
||||
"""
|
||||
self.buffer = ""
|
||||
self.max_buffer_words = max_buffer_words
|
||||
self.completed_sentences = deque()
|
||||
|
||||
# Sentence boundary patterns
|
||||
self.sentence_end_pattern = re.compile(r'([.!?]+)\s+')
|
||||
self.sentence_boundaries = re.compile(r'(?<=[.!?])\s+(?=[A-Z])')
|
||||
|
||||
def add_chunk(self, text: str) -> List[str]:
|
||||
"""
|
||||
Add a new transcription chunk and extract any complete sentences.
|
||||
|
||||
Args:
|
||||
text: New transcription text chunk
|
||||
|
||||
Returns:
|
||||
List of complete sentences extracted
|
||||
"""
|
||||
if not text or not text.strip():
|
||||
return []
|
||||
|
||||
# Add to buffer
|
||||
if self.buffer:
|
||||
# Smart joining: check if we need a space
|
||||
if not self.buffer[-1].isspace() and not text[0].isspace():
|
||||
self.buffer += " "
|
||||
self.buffer += text.strip()
|
||||
|
||||
# Extract complete sentences
|
||||
sentences = self._extract_sentences()
|
||||
|
||||
# Check if buffer is too large
|
||||
word_count = len(self.buffer.split())
|
||||
if word_count > self.max_buffer_words:
|
||||
# Force extraction of what we have
|
||||
forced = self._force_extract()
|
||||
if forced:
|
||||
sentences.extend(forced)
|
||||
|
||||
return sentences
|
||||
|
||||
def _extract_sentences(self) -> List[str]:
|
||||
"""
|
||||
Extract complete sentences from buffer.
|
||||
Keeps incomplete sentence in buffer.
|
||||
|
||||
Returns:
|
||||
List of complete sentences
|
||||
"""
|
||||
sentences = []
|
||||
|
||||
# Find sentence boundaries
|
||||
# Pattern: sentence ending punctuation followed by space and capital letter
|
||||
# or sentence ending at punctuation before end of buffer
|
||||
parts = self.sentence_boundaries.split(self.buffer)
|
||||
|
||||
if len(parts) > 1:
|
||||
# We have complete sentences
|
||||
# Keep the last part (incomplete sentence) in buffer
|
||||
sentences = [s.strip() for s in parts[:-1] if s.strip()]
|
||||
self.buffer = parts[-1].strip()
|
||||
|
||||
return sentences
|
||||
|
||||
def _force_extract(self) -> List[str]:
|
||||
"""
|
||||
Force extraction when buffer is too large.
|
||||
Tries to break at reasonable points.
|
||||
|
||||
Returns:
|
||||
List of extracted text segments
|
||||
"""
|
||||
# Try to find the last sentence-like boundary
|
||||
last_period = max(
|
||||
self.buffer.rfind('. '),
|
||||
self.buffer.rfind('! '),
|
||||
self.buffer.rfind('? ')
|
||||
)
|
||||
|
||||
if last_period > 0:
|
||||
# Extract up to last period
|
||||
extracted = self.buffer[:last_period + 1].strip()
|
||||
self.buffer = self.buffer[last_period + 1:].strip()
|
||||
return [extracted]
|
||||
else:
|
||||
# No sentence boundary found, extract by word limit
|
||||
words = self.buffer.split()
|
||||
if len(words) > self.max_buffer_words:
|
||||
# Take 80% of max_buffer_words
|
||||
split_point = int(self.max_buffer_words * 0.8)
|
||||
extracted = " ".join(words[:split_point])
|
||||
self.buffer = " ".join(words[split_point:])
|
||||
return [extracted + "..."]
|
||||
|
||||
return []
|
||||
|
||||
def flush(self) -> List[str]:
|
||||
"""
|
||||
Flush remaining buffer and return as sentence(s).
|
||||
Call this at end of transcription.
|
||||
|
||||
Returns:
|
||||
List of remaining text as sentences
|
||||
"""
|
||||
sentences = []
|
||||
|
||||
if self.buffer.strip():
|
||||
# Try to extract any remaining complete sentences first
|
||||
extracted = self._extract_sentences()
|
||||
sentences.extend(extracted)
|
||||
|
||||
# Return remaining buffer if it has content
|
||||
if self.buffer.strip():
|
||||
# Check if it ends with punctuation
|
||||
if not self.buffer[-1] in '.!?':
|
||||
self.buffer += "."
|
||||
sentences.append(self.buffer.strip())
|
||||
self.buffer = ""
|
||||
|
||||
return sentences
|
||||
|
||||
def get_buffer_status(self) -> dict:
|
||||
"""
|
||||
Get current buffer status for debugging.
|
||||
|
||||
Returns:
|
||||
Dictionary with buffer stats
|
||||
"""
|
||||
return {
|
||||
"buffer_length": len(self.buffer),
|
||||
"buffer_words": len(self.buffer.split()) if self.buffer else 0,
|
||||
"buffer_preview": self.buffer[:100] + "..." if len(self.buffer) > 100 else self.buffer
|
||||
}
|
||||
|
||||
|
||||
class SentenceCleaner:
|
||||
"""
|
||||
Cleans and normalizes extracted sentences.
|
||||
Removes duplicates, fixes common transcription issues.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.seen_sentences = set()
|
||||
self.similarity_threshold = 0.85
|
||||
|
||||
def clean(self, sentence: str) -> Optional[str]:
|
||||
"""
|
||||
Clean and normalize a sentence.
|
||||
|
||||
Args:
|
||||
sentence: Raw sentence text
|
||||
|
||||
Returns:
|
||||
Cleaned sentence or None if should be filtered
|
||||
"""
|
||||
if not sentence or not sentence.strip():
|
||||
return None
|
||||
|
||||
# Basic cleaning
|
||||
cleaned = sentence.strip()
|
||||
|
||||
# Remove multiple spaces
|
||||
cleaned = re.sub(r'\s+', ' ', cleaned)
|
||||
|
||||
# Fix spacing around punctuation
|
||||
cleaned = re.sub(r'\s+([.!?,;:])', r'\1', cleaned)
|
||||
|
||||
# Capitalize first letter
|
||||
if cleaned and not cleaned[0].isupper():
|
||||
cleaned = cleaned[0].upper() + cleaned[1:]
|
||||
|
||||
# Ensure ends with punctuation
|
||||
if cleaned and not cleaned[-1] in '.!?':
|
||||
cleaned += '.'
|
||||
|
||||
# Filter very short sentences (likely fragments)
|
||||
if len(cleaned.split()) < 3:
|
||||
return None
|
||||
|
||||
# Check for duplicates (exact)
|
||||
if cleaned in self.seen_sentences:
|
||||
return None
|
||||
|
||||
self.seen_sentences.add(cleaned)
|
||||
return cleaned
|
||||
|
||||
def reset(self):
|
||||
"""Reset seen sentences cache."""
|
||||
self.seen_sentences.clear()
|
||||
|
||||
|
||||
def demo():
|
||||
"""Demo usage of sentence extractor."""
|
||||
extractor = SentenceExtractor()
|
||||
cleaner = SentenceCleaner()
|
||||
|
||||
# Simulate chunked transcription
|
||||
chunks = [
|
||||
"Hello everyone welcome to",
|
||||
"to this presentation today we will",
|
||||
"will discuss the importance of AI. Artificial intelligence is",
|
||||
"is transforming many industries. It helps us automate",
|
||||
"automate tasks and make better decisions. What do you",
|
||||
"you think about this technology? I believe it has",
|
||||
"has great potential for the future."
|
||||
]
|
||||
|
||||
print("=== Sentence Extraction Demo ===\n")
|
||||
print("Input chunks:")
|
||||
for i, chunk in enumerate(chunks, 1):
|
||||
print(f" Chunk {i}: '{chunk}'")
|
||||
|
||||
print("\n" + "="*50)
|
||||
print("Extracted sentences:\n")
|
||||
|
||||
for i, chunk in enumerate(chunks, 1):
|
||||
sentences = extractor.add_chunk(chunk)
|
||||
for sent in sentences:
|
||||
cleaned = cleaner.clean(sent)
|
||||
if cleaned:
|
||||
print(f" [{i}] {cleaned}")
|
||||
|
||||
# Flush remaining buffer
|
||||
print("\nFlushing buffer...")
|
||||
final_sentences = extractor.flush()
|
||||
for sent in final_sentences:
|
||||
cleaned = cleaner.clean(sent)
|
||||
if cleaned:
|
||||
print(f" [final] {cleaned}")
|
||||
|
||||
print("\n" + "="*50)
|
||||
print("Buffer status:")
|
||||
print(extractor.get_buffer_status())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
demo()
|
||||
@@ -7,6 +7,7 @@
|
||||
<excludeFolder url="file://$MODULE_DIR$/.idea" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.13 (cli)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -1,596 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Real-time transcription of Windows speaker output using loopback capture.
|
||||
Captures system audio and transcribes with Whisper in near real-time.
|
||||
"""
|
||||
|
||||
import sounddevice as sd
|
||||
import numpy as np
|
||||
import threading
|
||||
import queue
|
||||
import time
|
||||
import os
|
||||
import argparse
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
# Choose your Whisper backend here:
|
||||
# For faster-whisper (recommended):
|
||||
from faster_whisper import WhisperModel
|
||||
|
||||
# LLM integration
|
||||
try:
|
||||
import ollama
|
||||
OLLAMA_AVAILABLE = True
|
||||
except ImportError:
|
||||
OLLAMA_AVAILABLE = False
|
||||
|
||||
|
||||
# # For regular whisper (comment out the line above and uncomment these):
|
||||
# import whisper
|
||||
|
||||
|
||||
class WindowsLoopbackAudioCapture:
|
||||
"""Capture Windows speaker output using WASAPI loopback"""
|
||||
|
||||
def __init__(self, device_name=None, sample_rate=16000, chunk_size=2048):
|
||||
self.sample_rate = sample_rate
|
||||
self.chunk_size = chunk_size
|
||||
|
||||
# Find loopback device
|
||||
self.device_info = self._find_loopback_device(device_name)
|
||||
if not self.device_info:
|
||||
raise RuntimeError(
|
||||
"No loopback device found.\n"
|
||||
"1. Ensure your speakers/headphones are connected\n"
|
||||
"2. Enable 'Stereo Mix' in Sound settings\n"
|
||||
"3. Or install VB-Cable virtual audio device"
|
||||
)
|
||||
|
||||
print(f"✓ Using device: {self.device_info['name']} (index {self.device_info['index']})")
|
||||
|
||||
# Queue for audio data
|
||||
self.audio_queue = queue.Queue()
|
||||
self.stop_event = threading.Event()
|
||||
|
||||
# Start the stream
|
||||
try:
|
||||
self.stream = sd.InputStream(
|
||||
device=self.device_info['index'],
|
||||
channels=1,
|
||||
samplerate=sample_rate,
|
||||
blocksize=chunk_size,
|
||||
dtype='int16',
|
||||
latency='low',
|
||||
callback=self._audio_callback
|
||||
)
|
||||
self.stream.start()
|
||||
print("✓ Audio capture stream started")
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"Failed to start audio stream: {e}")
|
||||
|
||||
def _find_loopback_device(self, device_name):
|
||||
"""Find the speaker device with loopback capability"""
|
||||
devices = sd.query_devices()
|
||||
|
||||
# If device name specified, find exact match
|
||||
if device_name:
|
||||
for dev in devices:
|
||||
if (device_name.lower() in dev['name'].lower() and
|
||||
dev['max_input_channels'] > 0):
|
||||
return dev
|
||||
|
||||
# Auto-detect: look for WASAPI speakers/headphones
|
||||
for dev in devices:
|
||||
if (dev['max_input_channels'] > 0 and
|
||||
any(x in dev['name'] for x in ['Speakers', 'Headphones', 'Output'])):
|
||||
return dev
|
||||
|
||||
# Fallback: Stereo Mix or similar
|
||||
for dev in devices:
|
||||
if 'Stereo Mix' in dev['name']:
|
||||
return dev
|
||||
|
||||
return None
|
||||
|
||||
def _audio_callback(self, indata, frames, time_info, status):
|
||||
"""Callback for audio data"""
|
||||
if status:
|
||||
print(f"⚠ Audio status: {status}")
|
||||
self.audio_queue.put(indata.copy())
|
||||
|
||||
def read_chunk(self):
|
||||
"""Read audio data from queue"""
|
||||
try:
|
||||
return self.audio_queue.get(timeout=0.05).flatten()
|
||||
except queue.Empty:
|
||||
return None
|
||||
|
||||
def close(self):
|
||||
"""Cleanup resources"""
|
||||
if hasattr(self, 'stream'):
|
||||
self.stream.stop()
|
||||
self.stream.close()
|
||||
|
||||
|
||||
class WhisperStreamTranscriber:
|
||||
"""Process audio chunks with Whisper/faster-whisper"""
|
||||
|
||||
def __init__(self, model_name="base", language="en", force_cpu=False):
|
||||
print(f"Loading Whisper model '{model_name}'...")
|
||||
|
||||
# Check for CUDA availability
|
||||
import torch
|
||||
has_cuda = torch.cuda.is_available() and not force_cpu
|
||||
|
||||
# Force CPU if CUDA libraries incompatible
|
||||
device = "cpu"
|
||||
compute_type = "int8"
|
||||
|
||||
if has_cuda:
|
||||
try:
|
||||
# Test if CTranslate2 can actually use CUDA
|
||||
import ctranslate2
|
||||
cuda_count = ctranslate2.get_cuda_device_count()
|
||||
if cuda_count > 0:
|
||||
device = "cuda"
|
||||
compute_type = "float16"
|
||||
print(f"Using device: cuda ({torch.cuda.get_device_name(0)})")
|
||||
else:
|
||||
print(f"CUDA available in PyTorch but not in CTranslate2. Using CPU.")
|
||||
except Exception as e:
|
||||
print(f"CUDA libraries not found ({e}). Using CPU.")
|
||||
else:
|
||||
print("Using device: cpu")
|
||||
|
||||
# FASTER-WHISPER (recommended):
|
||||
model_kwargs = {
|
||||
"device": device,
|
||||
"compute_type": compute_type
|
||||
}
|
||||
if not has_cuda:
|
||||
model_kwargs["cpu_threads"] = 4
|
||||
|
||||
self.model = WhisperModel(model_name, **model_kwargs)
|
||||
self.language = language
|
||||
self.audio_buffer = np.array([], dtype=np.float32)
|
||||
self.lock = threading.Lock()
|
||||
|
||||
# # REGULAR WHISPER:
|
||||
# self.model = whisper.load_model(model_name)
|
||||
# self.language = language
|
||||
# self.audio_buffer = np.array([], dtype=np.float32)
|
||||
# self.lock = threading.Lock()
|
||||
|
||||
def add_audio(self, audio_chunk):
|
||||
"""Add new audio data to buffer"""
|
||||
with self.lock:
|
||||
audio_float = audio_chunk.astype(np.float32) / 32768.0
|
||||
self.audio_buffer = np.concatenate([self.audio_buffer, audio_float])
|
||||
|
||||
def transcribe_chunk(self, min_duration=5.0):
|
||||
"""Transcribe accumulated audio if enough duration"""
|
||||
with self.lock:
|
||||
duration = len(self.audio_buffer) / 16000
|
||||
if duration < min_duration:
|
||||
return None
|
||||
|
||||
audio_to_process = self.audio_buffer.copy()
|
||||
self.audio_buffer = np.array([], dtype=np.float32)
|
||||
|
||||
# Process with FASTER-WHISPER:
|
||||
try:
|
||||
segments, _ = self.model.transcribe(
|
||||
audio_to_process,
|
||||
language=self.language,
|
||||
beam_size=5,
|
||||
vad_filter=True,
|
||||
vad_parameters=dict(min_silence_duration_ms=500),
|
||||
word_timestamps=False
|
||||
)
|
||||
text = " ".join([segment.text for segment in segments]).strip()
|
||||
return text if text else None
|
||||
except Exception as e:
|
||||
print(f"❌ Transcription error: {e}")
|
||||
return None
|
||||
|
||||
# # REGULAR WHISPER:
|
||||
# try:
|
||||
# result = self.model.transcribe(
|
||||
# audio_to_process,
|
||||
# language=self.language,
|
||||
# task="transcribe",
|
||||
# fp16=False
|
||||
# )
|
||||
# return result["text"].strip()
|
||||
# except Exception as e:
|
||||
# print(f"❌ Transcription error: {e}")
|
||||
# return None
|
||||
|
||||
|
||||
class LocalLLMAnalyzer:
|
||||
"""Local LLM for fact-checking and question generation using Ollama"""
|
||||
|
||||
def __init__(self, model="llama3.2"):
|
||||
if not OLLAMA_AVAILABLE:
|
||||
raise RuntimeError(
|
||||
"Ollama package not installed.\n"
|
||||
"Install with: pip install ollama"
|
||||
)
|
||||
|
||||
self.model = model
|
||||
self._test_connection()
|
||||
|
||||
def _test_connection(self):
|
||||
"""Test connection to Ollama service"""
|
||||
try:
|
||||
ollama.list()
|
||||
print(f"✓ Ollama connected using model: {self.model}")
|
||||
except Exception as e:
|
||||
raise RuntimeError(
|
||||
f"Cannot connect to Ollama. Ensure it's installed and running.\n"
|
||||
f"Error: {e}\n"
|
||||
f"Install from: https://ollama.ai\n"
|
||||
f"Then run: ollama pull {self.model}"
|
||||
)
|
||||
|
||||
def _extract_json(self, text):
|
||||
"""Extract JSON from text that might contain markdown or other formatting"""
|
||||
# Try to find JSON block in markdown code fence
|
||||
import re
|
||||
json_match = re.search(r'```(?:json)?\s*(\{.*?\})\s*```', text, re.DOTALL)
|
||||
if json_match:
|
||||
return json_match.group(1)
|
||||
|
||||
# Try to find raw JSON object
|
||||
json_match = re.search(r'\{.*\}', text, re.DOTALL)
|
||||
if json_match:
|
||||
return json_match.group(0)
|
||||
|
||||
return text
|
||||
|
||||
def fact_check(self, text, context=""):
|
||||
"""Analyze text for factual accuracy"""
|
||||
prompt = f"""You are a fact-checking assistant. Analyze this statement for factual accuracy.
|
||||
|
||||
Context: {context}
|
||||
Statement: "{text}"
|
||||
|
||||
You must respond with ONLY valid JSON in this exact format, no other text:
|
||||
{{
|
||||
"verdict": "factual",
|
||||
"confidence": 0.95,
|
||||
"explanation": "Brief explanation here",
|
||||
"sources": ["source1"],
|
||||
"corrections": ""
|
||||
}}
|
||||
|
||||
Valid verdict values: "factual", "dubious", "not_factual"
|
||||
Confidence must be a number between 0.0 and 1.0."""
|
||||
|
||||
try:
|
||||
response = ollama.generate(
|
||||
model=self.model,
|
||||
prompt=prompt,
|
||||
options={"temperature": 0.1, "num_predict": 200}
|
||||
)
|
||||
|
||||
# Extract and parse JSON
|
||||
response_text = response['response']
|
||||
json_text = self._extract_json(response_text)
|
||||
result = json.loads(json_text)
|
||||
|
||||
# Validate required fields
|
||||
if 'verdict' not in result or 'confidence' not in result:
|
||||
raise ValueError("Missing required fields")
|
||||
|
||||
# Ensure defaults for optional fields
|
||||
result.setdefault('explanation', 'No explanation provided')
|
||||
result.setdefault('sources', [])
|
||||
result.setdefault('corrections', '')
|
||||
|
||||
return result
|
||||
|
||||
except (json.JSONDecodeError, ValueError) as e:
|
||||
# Return a simple analysis without JSON parsing
|
||||
return {
|
||||
"verdict": "dubious",
|
||||
"confidence": 0.5,
|
||||
"explanation": f"Could not parse LLM response properly. Model may need JSON format support.",
|
||||
"sources": [],
|
||||
"corrections": ""
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"verdict": "error",
|
||||
"confidence": 0.0,
|
||||
"explanation": f"Analysis failed: {str(e)}",
|
||||
"sources": [],
|
||||
"corrections": ""
|
||||
}
|
||||
|
||||
def generate_augmenting_questions(self, text, context=""):
|
||||
"""Generate insightful questions based on the text"""
|
||||
prompt = f"""Based on this statement, generate 3 insightful questions that would help understand the topic better.
|
||||
|
||||
Statement: "{text}"
|
||||
Context: {context}
|
||||
|
||||
Respond with JSON only:
|
||||
{{
|
||||
"questions": ["Question 1", "Question 2", "Question 3"],
|
||||
"topics": ["key_topic_1", "key_topic_2"]
|
||||
}}"""
|
||||
|
||||
try:
|
||||
response = ollama.generate(
|
||||
model=self.model,
|
||||
prompt=prompt,
|
||||
format="json",
|
||||
options={"temperature": 0.7}
|
||||
)
|
||||
return json.loads(response['response'])
|
||||
except json.JSONDecodeError:
|
||||
return {
|
||||
"questions": ["Error: LLM response was not valid JSON"],
|
||||
"topics": []
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"questions": [f"Error: {str(e)}"],
|
||||
"topics": []
|
||||
}
|
||||
|
||||
|
||||
def list_audio_devices():
|
||||
"""Print all available audio input devices"""
|
||||
print("\nAvailable audio capture devices:")
|
||||
devices = sd.query_devices()
|
||||
for i, dev in enumerate(devices):
|
||||
if dev['max_input_channels'] > 0:
|
||||
print(f" [{i}] {dev['name']}")
|
||||
print(f" Channels: {dev['max_input_channels']} | Sample Rate: {dev['default_samplerate']}")
|
||||
print()
|
||||
|
||||
|
||||
def save_transcript(text, timestamp, filename):
|
||||
"""Append transcript to file"""
|
||||
os.makedirs(os.path.dirname(filename) if os.path.dirname(filename) else '.', exist_ok=True)
|
||||
with open(filename, "a", encoding="utf-8") as f:
|
||||
f.write(f"[{timestamp}] {text}\n")
|
||||
|
||||
|
||||
def save_enriched_transcript(data, filename):
|
||||
"""Save enriched transcript with LLM analysis"""
|
||||
os.makedirs(os.path.dirname(filename) if os.path.dirname(filename) else '.', exist_ok=True)
|
||||
with open(filename, "a", encoding="utf-8") as f:
|
||||
f.write(f"\n{'='*70}\n")
|
||||
f.write(f"[{data['timestamp']}] {data['text']}\n\n")
|
||||
|
||||
if 'fact_check' in data:
|
||||
fc = data['fact_check']
|
||||
f.write(f"📊 Fact Check: {fc.get('verdict', 'N/A').upper()} "
|
||||
f"(confidence: {fc.get('confidence', 0):.2f})\n")
|
||||
f.write(f"💡 {fc.get('explanation', 'N/A')}\n")
|
||||
if fc.get('corrections'):
|
||||
f.write(f"✏️ Correction: {fc['corrections']}\n")
|
||||
f.write("\n")
|
||||
|
||||
if 'questions' in data and data['questions'].get('questions'):
|
||||
f.write("❓ Questions:\n")
|
||||
for i, q in enumerate(data['questions']['questions'], 1):
|
||||
f.write(f"{i}. {q}\n")
|
||||
f.write("\n")
|
||||
|
||||
|
||||
def display_enriched_output(text, timestamp, fact_check=None, questions=None):
|
||||
"""Display transcript with LLM analysis"""
|
||||
print(f"\n[{timestamp}] {text}")
|
||||
|
||||
if fact_check:
|
||||
verdict_emoji = {
|
||||
'factual': '✅',
|
||||
'dubious': '⚠️',
|
||||
'not_factual': '❌',
|
||||
'error': '⚠️'
|
||||
}
|
||||
emoji = verdict_emoji.get(fact_check.get('verdict', 'error'), '❓')
|
||||
|
||||
print(f"\n{emoji} Fact Check: {fact_check.get('verdict', 'N/A').upper()} "
|
||||
f"(confidence: {fact_check.get('confidence', 0):.2f})")
|
||||
print(f"💡 {fact_check.get('explanation', 'N/A')}")
|
||||
|
||||
if fact_check.get('corrections'):
|
||||
print(f"✏️ Correction: {fact_check['corrections']}")
|
||||
|
||||
if questions and questions.get('questions'):
|
||||
print(f"\n❓ Questions:")
|
||||
for i, q in enumerate(questions['questions'], 1):
|
||||
print(f" {i}. {q}")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Real-time transcription of Windows speaker output",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Examples:
|
||||
python transcribe_speakers.py
|
||||
python transcribe_speakers.py --model small --language es --interval 5
|
||||
python transcribe_speakers.py --device "Speakers" --output "meeting.txt"
|
||||
python transcribe_speakers.py --model medium --interval 10 --output transcripts/live.txt
|
||||
"""
|
||||
)
|
||||
|
||||
parser.add_argument("--model", default="base",
|
||||
choices=["tiny", "base", "small", "medium", "large"],
|
||||
help="Whisper model size (default: base)")
|
||||
parser.add_argument("--language", default="en",
|
||||
help="Language code (default: en)")
|
||||
parser.add_argument("--device", metavar="NAME",
|
||||
help="Audio device name (partial match). If not specified, auto-detects")
|
||||
parser.add_argument("--interval", type=float, default=8.0,
|
||||
help="Processing interval in seconds (default: 8.0)")
|
||||
parser.add_argument("--output", "-o", metavar="FILE",
|
||||
help="Save transcript to file (e.g., transcript.txt)")
|
||||
parser.add_argument("--list-devices", action="store_true",
|
||||
help="List all available audio devices and exit")
|
||||
parser.add_argument("--force-cpu", action="store_true",
|
||||
help="Force CPU processing (disable GPU acceleration)")
|
||||
parser.add_argument("--enable-llm", action="store_true",
|
||||
help="Enable LLM analysis (fact-checking and questions)")
|
||||
parser.add_argument("--llm-model", default="gpt-oss:20b",
|
||||
help="Ollama model to use for LLM analysis (default: gpt-oss:20b)")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.list_devices:
|
||||
list_audio_devices()
|
||||
return
|
||||
|
||||
print("=== Windows Real-Time Audio Transcription ===")
|
||||
print(f"Model: {args.model} | Language: {args.language} | Interval: {args.interval}s")
|
||||
if args.output:
|
||||
print(f"Output: {args.output}")
|
||||
if args.enable_llm:
|
||||
print(f"LLM Analysis: Enabled ({args.llm_model})")
|
||||
|
||||
# Initialize audio capture
|
||||
try:
|
||||
capturer = WindowsLoopbackAudioCapture(
|
||||
device_name=args.device,
|
||||
sample_rate=16000,
|
||||
chunk_size=2048
|
||||
)
|
||||
except RuntimeError as e:
|
||||
print(f"\n❌ Audio Error: {e}")
|
||||
print("\nTo fix this:")
|
||||
print("1. Right-click speaker icon → Sounds → Recording tab")
|
||||
print("2. Right-click in empty area → Show Disabled Devices")
|
||||
print("3. Enable 'Stereo Mix' → Set as Default Device")
|
||||
print("\nAlternative: Install VB-Cable (free) from vb-audio.com")
|
||||
print(" Then use: --device 'CABLE Output'")
|
||||
list_audio_devices()
|
||||
return
|
||||
|
||||
# Initialize transcriber
|
||||
try:
|
||||
transcriber = WhisperStreamTranscriber(
|
||||
model_name=args.model,
|
||||
language=args.language,
|
||||
force_cpu=args.force_cpu
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"\n❌ Model Error: {e}")
|
||||
print("Make sure you installed Whisper correctly")
|
||||
return
|
||||
|
||||
# Initialize LLM analyzer (optional)
|
||||
llm_analyzer = None
|
||||
if args.enable_llm:
|
||||
try:
|
||||
llm_analyzer = LocalLLMAnalyzer(model=args.llm_model)
|
||||
except RuntimeError as e:
|
||||
print(f"\n❌ LLM Error: {e}")
|
||||
print("Continuing without LLM analysis...")
|
||||
llm_analyzer = None
|
||||
|
||||
# Main processing loop
|
||||
print(f"\n✅ Started transcription. Press Ctrl+C to stop.\n{'=' * 50}")
|
||||
last_process_time = time.time()
|
||||
total_duration = 0
|
||||
segment_count = 0
|
||||
|
||||
try:
|
||||
while True:
|
||||
# Collect audio
|
||||
chunk = capturer.read_chunk()
|
||||
if chunk is not None:
|
||||
transcriber.add_audio(chunk)
|
||||
total_duration += len(chunk) / 16000
|
||||
|
||||
# Process at intervals
|
||||
current_time = time.time()
|
||||
if current_time - last_process_time >= args.interval:
|
||||
text = transcriber.transcribe_chunk()
|
||||
if text:
|
||||
segment_count += 1
|
||||
timestamp = datetime.now().strftime("%H:%M:%S")
|
||||
|
||||
# LLM Analysis
|
||||
fact_check = None
|
||||
questions = None
|
||||
if llm_analyzer:
|
||||
context = f"Segment {segment_count}"
|
||||
fact_check = llm_analyzer.fact_check(text, context)
|
||||
questions = llm_analyzer.generate_augmenting_questions(text, context)
|
||||
|
||||
# Display output
|
||||
if llm_analyzer:
|
||||
display_enriched_output(text, timestamp, fact_check, questions)
|
||||
else:
|
||||
print(f"[{timestamp}] {text}")
|
||||
|
||||
# Save output
|
||||
if args.output:
|
||||
if llm_analyzer:
|
||||
data = {
|
||||
'timestamp': timestamp,
|
||||
'text': text,
|
||||
'fact_check': fact_check,
|
||||
'questions': questions
|
||||
}
|
||||
save_enriched_transcript(data, args.output)
|
||||
else:
|
||||
save_transcript(text, timestamp, args.output)
|
||||
|
||||
last_process_time = current_time
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print(f"\n{'=' * 50}\n🛑 Stopping transcription...")
|
||||
|
||||
# Cleanup
|
||||
capturer.close()
|
||||
|
||||
# Process remaining audio
|
||||
print("\nProcessing remaining audio...")
|
||||
final_text = transcriber.transcribe_chunk(min_duration=0)
|
||||
if final_text:
|
||||
timestamp = datetime.now().strftime("%H:%M:%S")
|
||||
|
||||
# LLM Analysis for final segment
|
||||
fact_check = None
|
||||
questions = None
|
||||
if llm_analyzer:
|
||||
fact_check = llm_analyzer.fact_check(final_text, "Final segment")
|
||||
questions = llm_analyzer.generate_augmenting_questions(final_text)
|
||||
|
||||
# Display output
|
||||
if llm_analyzer:
|
||||
display_enriched_output(final_text, timestamp, fact_check, questions)
|
||||
else:
|
||||
print(f"[{timestamp}] {final_text}")
|
||||
|
||||
# Save output
|
||||
if args.output:
|
||||
if llm_analyzer:
|
||||
data = {
|
||||
'timestamp': timestamp,
|
||||
'text': final_text,
|
||||
'fact_check': fact_check,
|
||||
'questions': questions
|
||||
}
|
||||
save_enriched_transcript(data, args.output)
|
||||
else:
|
||||
save_transcript(final_text, timestamp, args.output)
|
||||
|
||||
# Summary
|
||||
print(f"\n✅ Complete! Processed {total_duration:.1f}s of audio")
|
||||
print(f" Generated {segment_count} transcript segments")
|
||||
if args.output and os.path.exists(args.output):
|
||||
abs_path = os.path.abspath(args.output)
|
||||
print(f"💾 Transcript saved to: {abs_path}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -15,11 +15,13 @@ import json
|
||||
from datetime import datetime
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
|
||||
# Choose your Whisper backend here:
|
||||
# For faster-whisper (recommended):
|
||||
# Whisper transcription (using faster-whisper for optimal performance)
|
||||
from faster_whisper import WhisperModel
|
||||
|
||||
# LLM integration
|
||||
# Sentence extraction for stitching chunks
|
||||
from sentence_extractor import SentenceExtractor, SentenceCleaner
|
||||
|
||||
# LLM integration (optional)
|
||||
try:
|
||||
import ollama
|
||||
OLLAMA_AVAILABLE = True
|
||||
@@ -27,10 +29,6 @@ except ImportError:
|
||||
OLLAMA_AVAILABLE = False
|
||||
|
||||
|
||||
# # For regular whisper (comment out the line above and uncomment these):
|
||||
# import whisper
|
||||
|
||||
|
||||
class WindowsLoopbackAudioCapture:
|
||||
"""Capture Windows speaker output using WASAPI loopback"""
|
||||
|
||||
@@ -170,12 +168,6 @@ class WhisperStreamTranscriber:
|
||||
self.audio_buffer = np.array([], dtype=np.float32)
|
||||
self.lock = threading.Lock()
|
||||
|
||||
# # REGULAR WHISPER:
|
||||
# self.model = whisper.load_model(model_name)
|
||||
# self.language = language
|
||||
# self.audio_buffer = np.array([], dtype=np.float32)
|
||||
# self.lock = threading.Lock()
|
||||
|
||||
def add_audio(self, audio_chunk):
|
||||
"""Add new audio data to buffer"""
|
||||
with self.lock:
|
||||
@@ -222,19 +214,6 @@ class WhisperStreamTranscriber:
|
||||
print(f"❌ Transcription error: {e}")
|
||||
return None
|
||||
|
||||
# # REGULAR WHISPER:
|
||||
# try:
|
||||
# result = self.model.transcribe(
|
||||
# audio_to_process,
|
||||
# language=self.language,
|
||||
# task="transcribe",
|
||||
# fp16=False
|
||||
# )
|
||||
# return result["text"].strip()
|
||||
# except Exception as e:
|
||||
# print(f"❌ Transcription error: {e}")
|
||||
# return None
|
||||
|
||||
|
||||
class LocalLLMAnalyzer:
|
||||
"""Local LLM for fact-checking and question generation using Ollama"""
|
||||
@@ -536,6 +515,8 @@ Examples:
|
||||
help="Ollama model to use for LLM analysis (default: gpt-oss:20b)")
|
||||
parser.add_argument("--llm-debug", action="store_true",
|
||||
help="Show LLM raw responses for debugging")
|
||||
parser.add_argument("--sentence-mode", action="store_true",
|
||||
help="Extract complete sentences by stitching chunks together")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -549,6 +530,8 @@ Examples:
|
||||
print(f"Output: {args.output}")
|
||||
if args.enable_llm:
|
||||
print(f"LLM Analysis: Enabled ({args.llm_model})")
|
||||
if args.sentence_mode:
|
||||
print(f"Sentence Mode: Enabled (stitching chunks into complete sentences)")
|
||||
|
||||
# Initialize audio capture
|
||||
try:
|
||||
@@ -591,6 +574,14 @@ Examples:
|
||||
print("Continuing without LLM analysis...")
|
||||
llm_analyzer = None
|
||||
|
||||
# Initialize sentence extractor (optional)
|
||||
sentence_extractor = None
|
||||
sentence_cleaner = None
|
||||
if args.sentence_mode:
|
||||
sentence_extractor = SentenceExtractor(max_buffer_words=150)
|
||||
sentence_cleaner = SentenceCleaner()
|
||||
print("✓ Sentence extraction initialized")
|
||||
|
||||
# Main processing loop
|
||||
print(f"\n✅ Started transcription. Press Ctrl+C to stop.\n{'=' * 50}")
|
||||
last_process_time = time.time()
|
||||
@@ -620,11 +611,45 @@ Examples:
|
||||
segment_count += 1
|
||||
timestamp = datetime.now().strftime("%H:%M:%S")
|
||||
|
||||
# Sentence extraction mode
|
||||
if sentence_extractor:
|
||||
# Add chunk to extractor and get complete sentences
|
||||
sentences = sentence_extractor.add_chunk(text)
|
||||
|
||||
for sentence in sentences:
|
||||
# Clean the sentence
|
||||
cleaned = sentence_cleaner.clean(sentence) if sentence_cleaner else sentence
|
||||
if cleaned:
|
||||
print(f"[{timestamp}] 📝 {cleaned}")
|
||||
|
||||
# Save individual sentences
|
||||
if args.output and not llm_analyzer:
|
||||
save_transcript(cleaned, timestamp, args.output)
|
||||
|
||||
# LLM analysis on complete sentences
|
||||
if llm_analyzer:
|
||||
context = f"Sentence from segment {segment_count}"
|
||||
|
||||
def run_llm_analysis(txt, ctx, ts, seg_num):
|
||||
fc = llm_analyzer.fact_check(txt, ctx)
|
||||
qs = llm_analyzer.generate_augmenting_questions(txt, ctx)
|
||||
return {
|
||||
'timestamp': ts,
|
||||
'text': txt,
|
||||
'segment_count': seg_num,
|
||||
'fact_check': fc,
|
||||
'questions': qs
|
||||
}
|
||||
|
||||
future = llm_executor.submit(run_llm_analysis, cleaned, context, timestamp, segment_count)
|
||||
pending_llm_tasks[segment_count] = future
|
||||
else:
|
||||
# Standard mode: display chunks as-is
|
||||
# Display transcription immediately (don't wait for LLM)
|
||||
print(f"[{timestamp}] {text}")
|
||||
|
||||
# LLM Analysis (run concurrently in background)
|
||||
if llm_analyzer:
|
||||
# LLM Analysis (run concurrently in background) - only in non-sentence mode
|
||||
if llm_analyzer and not sentence_extractor:
|
||||
context = f"Segment {segment_count}"
|
||||
|
||||
# Submit LLM tasks to thread pool
|
||||
@@ -701,6 +726,34 @@ Examples:
|
||||
# Cleanup
|
||||
capturer.close()
|
||||
|
||||
# Flush sentence buffer if in sentence mode
|
||||
if sentence_extractor:
|
||||
print("\n📝 Flushing sentence buffer...")
|
||||
final_sentences = sentence_extractor.flush()
|
||||
for sentence in final_sentences:
|
||||
cleaned = sentence_cleaner.clean(sentence) if sentence_cleaner else sentence
|
||||
if cleaned:
|
||||
timestamp = datetime.now().strftime("%H:%M:%S")
|
||||
print(f"[{timestamp}] 📝 {cleaned}")
|
||||
|
||||
if args.output and not llm_analyzer:
|
||||
save_transcript(cleaned, timestamp, args.output)
|
||||
|
||||
# LLM analysis for flushed sentences
|
||||
if llm_analyzer:
|
||||
fact_check = llm_analyzer.fact_check(cleaned, "Final sentence")
|
||||
questions = llm_analyzer.generate_augmenting_questions(cleaned)
|
||||
display_enriched_output(cleaned, timestamp, fact_check, questions)
|
||||
|
||||
if args.output:
|
||||
data = {
|
||||
'timestamp': timestamp,
|
||||
'text': cleaned,
|
||||
'fact_check': fact_check,
|
||||
'questions': questions
|
||||
}
|
||||
save_enriched_transcript(data, args.output)
|
||||
|
||||
# Process remaining audio
|
||||
print("\nProcessing remaining audio...")
|
||||
final_text = transcriber.transcribe_chunk(min_duration=0)
|
||||
|
||||
@@ -1,636 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Real-time transcription of Windows speaker output using loopback capture.
|
||||
Captures system audio and transcribes with Whisper in near real-time.
|
||||
"""
|
||||
|
||||
import sounddevice as sd
|
||||
import numpy as np
|
||||
import threading
|
||||
import queue
|
||||
import time
|
||||
import os
|
||||
import argparse
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
# Choose your Whisper backend here:
|
||||
# For faster-whisper (recommended):
|
||||
from faster_whisper import WhisperModel
|
||||
|
||||
# LLM integration
|
||||
try:
|
||||
import ollama
|
||||
OLLAMA_AVAILABLE = True
|
||||
except ImportError:
|
||||
OLLAMA_AVAILABLE = False
|
||||
|
||||
|
||||
# # For regular whisper (comment out the line above and uncomment these):
|
||||
# import whisper
|
||||
|
||||
|
||||
class WindowsLoopbackAudioCapture:
|
||||
"""Capture Windows speaker output using WASAPI loopback"""
|
||||
|
||||
def __init__(self, device_name=None, sample_rate=16000, chunk_size=2048):
|
||||
self.sample_rate = sample_rate
|
||||
self.chunk_size = chunk_size
|
||||
|
||||
# Find loopback device
|
||||
self.device_info = self._find_loopback_device(device_name)
|
||||
if not self.device_info:
|
||||
raise RuntimeError(
|
||||
"No loopback device found.\n"
|
||||
"1. Ensure your speakers/headphones are connected\n"
|
||||
"2. Enable 'Stereo Mix' in Sound settings\n"
|
||||
"3. Or install VB-Cable virtual audio device"
|
||||
)
|
||||
|
||||
print(f"✓ Using device: {self.device_info['name']} (index {self.device_info['index']})")
|
||||
|
||||
# Queue for audio data
|
||||
self.audio_queue = queue.Queue()
|
||||
self.stop_event = threading.Event()
|
||||
|
||||
# Start the stream
|
||||
try:
|
||||
self.stream = sd.InputStream(
|
||||
device=self.device_info['index'],
|
||||
channels=1,
|
||||
samplerate=sample_rate,
|
||||
blocksize=chunk_size,
|
||||
dtype='int16',
|
||||
latency='low',
|
||||
callback=self._audio_callback
|
||||
)
|
||||
self.stream.start()
|
||||
print("✓ Audio capture stream started")
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"Failed to start audio stream: {e}")
|
||||
|
||||
def _find_loopback_device(self, device_name):
|
||||
"""Find the speaker device with loopback capability"""
|
||||
devices = sd.query_devices()
|
||||
|
||||
# If device name specified, find exact match
|
||||
if device_name:
|
||||
for dev in devices:
|
||||
if (device_name.lower() in dev['name'].lower() and
|
||||
dev['max_input_channels'] > 0):
|
||||
return dev
|
||||
|
||||
# Auto-detect: look for WASAPI speakers/headphones
|
||||
for dev in devices:
|
||||
if (dev['max_input_channels'] > 0 and
|
||||
any(x in dev['name'] for x in ['Speakers', 'Headphones', 'Output'])):
|
||||
return dev
|
||||
|
||||
# Fallback: Stereo Mix or similar
|
||||
for dev in devices:
|
||||
if 'Stereo Mix' in dev['name']:
|
||||
return dev
|
||||
|
||||
return None
|
||||
|
||||
def _audio_callback(self, indata, frames, time_info, status):
|
||||
"""Callback for audio data"""
|
||||
if status:
|
||||
print(f"⚠ Audio status: {status}")
|
||||
self.audio_queue.put(indata.copy())
|
||||
|
||||
def read_chunk(self):
|
||||
"""Read audio data from queue"""
|
||||
try:
|
||||
return self.audio_queue.get(timeout=0.05).flatten()
|
||||
except queue.Empty:
|
||||
return None
|
||||
|
||||
def close(self):
|
||||
"""Cleanup resources"""
|
||||
if hasattr(self, 'stream'):
|
||||
self.stream.stop()
|
||||
self.stream.close()
|
||||
|
||||
|
||||
class WhisperStreamTranscriber:
|
||||
"""Process audio chunks with Whisper/faster-whisper"""
|
||||
|
||||
def __init__(self, model_name="base", language="en", force_cpu=False):
|
||||
print(f"Loading Whisper model '{model_name}'...")
|
||||
|
||||
# Check for CUDA availability
|
||||
import torch
|
||||
has_cuda = torch.cuda.is_available() and not force_cpu
|
||||
|
||||
# Force CPU if CUDA libraries incompatible
|
||||
device = "cpu"
|
||||
compute_type = "int8"
|
||||
|
||||
if has_cuda:
|
||||
try:
|
||||
# Test if CTranslate2 can actually use CUDA
|
||||
import ctranslate2
|
||||
cuda_count = ctranslate2.get_cuda_device_count()
|
||||
if cuda_count > 0:
|
||||
device = "cuda"
|
||||
compute_type = "float16"
|
||||
print(f"Using device: cuda ({torch.cuda.get_device_name(0)})")
|
||||
else:
|
||||
print(f"CUDA available in PyTorch but not in CTranslate2. Using CPU.")
|
||||
except Exception as e:
|
||||
print(f"CUDA libraries not found ({e}). Using CPU.")
|
||||
else:
|
||||
print("Using device: cpu")
|
||||
|
||||
# FASTER-WHISPER (recommended):
|
||||
model_kwargs = {
|
||||
"device": device,
|
||||
"compute_type": compute_type
|
||||
}
|
||||
if not has_cuda:
|
||||
model_kwargs["cpu_threads"] = 4
|
||||
|
||||
self.model = WhisperModel(model_name, **model_kwargs)
|
||||
self.language = language
|
||||
self.audio_buffer = np.array([], dtype=np.float32)
|
||||
self.lock = threading.Lock()
|
||||
|
||||
# # REGULAR WHISPER:
|
||||
# self.model = whisper.load_model(model_name)
|
||||
# self.language = language
|
||||
# self.audio_buffer = np.array([], dtype=np.float32)
|
||||
# self.lock = threading.Lock()
|
||||
|
||||
def add_audio(self, audio_chunk):
|
||||
"""Add new audio data to buffer"""
|
||||
with self.lock:
|
||||
audio_float = audio_chunk.astype(np.float32) / 32768.0
|
||||
self.audio_buffer = np.concatenate([self.audio_buffer, audio_float])
|
||||
|
||||
def transcribe_chunk(self, min_duration=5.0):
|
||||
"""Transcribe accumulated audio if enough duration"""
|
||||
with self.lock:
|
||||
duration = len(self.audio_buffer) / 16000
|
||||
if duration < min_duration:
|
||||
return None
|
||||
|
||||
audio_to_process = self.audio_buffer.copy()
|
||||
self.audio_buffer = np.array([], dtype=np.float32)
|
||||
|
||||
# Process with FASTER-WHISPER:
|
||||
try:
|
||||
segments, _ = self.model.transcribe(
|
||||
audio_to_process,
|
||||
language=self.language,
|
||||
beam_size=5,
|
||||
vad_filter=True,
|
||||
vad_parameters=dict(min_silence_duration_ms=500),
|
||||
word_timestamps=False
|
||||
)
|
||||
text = " ".join([segment.text for segment in segments]).strip()
|
||||
return text if text else None
|
||||
except Exception as e:
|
||||
print(f"❌ Transcription error: {e}")
|
||||
return None
|
||||
|
||||
# # REGULAR WHISPER:
|
||||
# try:
|
||||
# result = self.model.transcribe(
|
||||
# audio_to_process,
|
||||
# language=self.language,
|
||||
# task="transcribe",
|
||||
# fp16=False
|
||||
# )
|
||||
# return result["text"].strip()
|
||||
# except Exception as e:
|
||||
# print(f"❌ Transcription error: {e}")
|
||||
# return None
|
||||
|
||||
|
||||
class LocalLLMAnalyzer:
|
||||
"""Local LLM for fact-checking and question generation using Ollama"""
|
||||
|
||||
def __init__(self, model="llama3.2", debug=False):
|
||||
if not OLLAMA_AVAILABLE:
|
||||
raise RuntimeError(
|
||||
"Ollama package not installed.\n"
|
||||
"Install with: pip install ollama"
|
||||
)
|
||||
|
||||
self.model = model
|
||||
self.debug = debug
|
||||
self._test_connection()
|
||||
|
||||
def _test_connection(self):
|
||||
"""Test connection to Ollama service"""
|
||||
try:
|
||||
ollama.list()
|
||||
print(f"✓ Ollama connected using model: {self.model}")
|
||||
except Exception as e:
|
||||
raise RuntimeError(
|
||||
f"Cannot connect to Ollama. Ensure it's installed and running.\n"
|
||||
f"Error: {e}\n"
|
||||
f"Install from: https://ollama.ai\n"
|
||||
f"Then run: ollama pull {self.model}"
|
||||
)
|
||||
|
||||
def _extract_json(self, text):
|
||||
"""Extract JSON from text that might contain markdown or other formatting"""
|
||||
# Try to find JSON block in markdown code fence
|
||||
import re
|
||||
json_match = re.search(r'```(?:json)?\s*(\{.*?\})\s*```', text, re.DOTALL)
|
||||
if json_match:
|
||||
return json_match.group(1)
|
||||
|
||||
# Try to find raw JSON object
|
||||
json_match = re.search(r'\{.*\}', text, re.DOTALL)
|
||||
if json_match:
|
||||
return json_match.group(0)
|
||||
|
||||
return text
|
||||
|
||||
def fact_check(self, text, context=""):
|
||||
"""Analyze text for factual accuracy"""
|
||||
# Try simple structured format first
|
||||
prompt = f"""Analyze this for accuracy. Reply in this exact format:
|
||||
|
||||
VERDICT: [factual/dubious/not_factual]
|
||||
CONFIDENCE: [0.0-1.0]
|
||||
EXPLANATION: [one sentence]
|
||||
|
||||
Statement: "{text}"
|
||||
"""
|
||||
|
||||
try:
|
||||
response = ollama.generate(
|
||||
model=self.model,
|
||||
prompt=prompt,
|
||||
options={"temperature": 0.1, "num_predict": 150}
|
||||
)
|
||||
|
||||
response_text = response['response'].strip()
|
||||
|
||||
if self.debug:
|
||||
print(f"\n[DEBUG] Fact-check response:\n{response_text}\n")
|
||||
|
||||
# Try to parse structured text format
|
||||
verdict = "dubious"
|
||||
confidence = 0.5
|
||||
explanation = response_text
|
||||
|
||||
# Extract VERDICT
|
||||
import re
|
||||
verdict_match = re.search(r'VERDICT:\s*(\w+)', response_text, re.IGNORECASE)
|
||||
if verdict_match:
|
||||
verdict = verdict_match.group(1).lower()
|
||||
|
||||
# Extract CONFIDENCE
|
||||
conf_match = re.search(r'CONFIDENCE:\s*([\d.]+)', response_text, re.IGNORECASE)
|
||||
if conf_match:
|
||||
try:
|
||||
confidence = float(conf_match.group(1))
|
||||
confidence = max(0.0, min(1.0, confidence)) # Clamp to 0-1
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# Extract EXPLANATION
|
||||
expl_match = re.search(r'EXPLANATION:\s*(.+?)(?:\n|$)', response_text, re.IGNORECASE | re.DOTALL)
|
||||
if expl_match:
|
||||
explanation = expl_match.group(1).strip()
|
||||
|
||||
return {
|
||||
"verdict": verdict,
|
||||
"confidence": confidence,
|
||||
"explanation": explanation[:200], # Truncate if too long
|
||||
"sources": [],
|
||||
"corrections": ""
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
if self.debug:
|
||||
print(f"[DEBUG] Fact-check error: {e}")
|
||||
return {
|
||||
"verdict": "error",
|
||||
"confidence": 0.0,
|
||||
"explanation": f"Analysis failed: {str(e)}",
|
||||
"sources": [],
|
||||
"corrections": ""
|
||||
}
|
||||
|
||||
def generate_augmenting_questions(self, text, context=""):
|
||||
"""Generate insightful questions based on the text"""
|
||||
prompt = f"""Generate 3 questions about this. Reply in this exact format:
|
||||
|
||||
Q1: [question]
|
||||
Q2: [question]
|
||||
Q3: [question]
|
||||
|
||||
Statement: "{text}"
|
||||
"""
|
||||
|
||||
try:
|
||||
response = ollama.generate(
|
||||
model=self.model,
|
||||
prompt=prompt,
|
||||
options={"temperature": 0.7, "num_predict": 150}
|
||||
)
|
||||
|
||||
response_text = response['response'].strip()
|
||||
|
||||
if self.debug:
|
||||
print(f"\n[DEBUG] Questions response:\n{response_text}\n")
|
||||
|
||||
# Extract questions
|
||||
import re
|
||||
questions = []
|
||||
for i in range(1, 4):
|
||||
q_match = re.search(rf'Q{i}:\s*(.+?)(?:\n|$)', response_text, re.IGNORECASE)
|
||||
if q_match:
|
||||
questions.append(q_match.group(1).strip())
|
||||
|
||||
# If we couldn't parse, try to split by newlines and take first 3 non-empty lines
|
||||
if len(questions) < 3:
|
||||
lines = [line.strip() for line in response_text.split('\n') if line.strip()]
|
||||
questions = lines[:3] if lines else [
|
||||
"What are the key points here?",
|
||||
"What evidence supports this?",
|
||||
"What are the implications?"
|
||||
]
|
||||
|
||||
# Ensure we have exactly 3 questions
|
||||
while len(questions) < 3:
|
||||
questions.append("What else should we consider?")
|
||||
|
||||
return {
|
||||
"questions": questions[:3],
|
||||
"topics": []
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
if self.debug:
|
||||
print(f"[DEBUG] Questions error: {e}")
|
||||
return {
|
||||
"questions": [
|
||||
"What are the key points?",
|
||||
"What supports this claim?",
|
||||
"What are the implications?"
|
||||
],
|
||||
"topics": []
|
||||
}
|
||||
|
||||
|
||||
def list_audio_devices():
|
||||
"""Print all available audio input devices"""
|
||||
print("\nAvailable audio capture devices:")
|
||||
devices = sd.query_devices()
|
||||
for i, dev in enumerate(devices):
|
||||
if dev['max_input_channels'] > 0:
|
||||
print(f" [{i}] {dev['name']}")
|
||||
print(f" Channels: {dev['max_input_channels']} | Sample Rate: {dev['default_samplerate']}")
|
||||
print()
|
||||
|
||||
|
||||
def save_transcript(text, timestamp, filename):
|
||||
"""Append transcript to file"""
|
||||
os.makedirs(os.path.dirname(filename) if os.path.dirname(filename) else '.', exist_ok=True)
|
||||
with open(filename, "a", encoding="utf-8") as f:
|
||||
f.write(f"[{timestamp}] {text}\n")
|
||||
|
||||
|
||||
def save_enriched_transcript(data, filename):
|
||||
"""Save enriched transcript with LLM analysis"""
|
||||
os.makedirs(os.path.dirname(filename) if os.path.dirname(filename) else '.', exist_ok=True)
|
||||
with open(filename, "a", encoding="utf-8") as f:
|
||||
f.write(f"\n{'='*70}\n")
|
||||
f.write(f"[{data['timestamp']}] {data['text']}\n\n")
|
||||
|
||||
if 'fact_check' in data:
|
||||
fc = data['fact_check']
|
||||
f.write(f"📊 Fact Check: {fc.get('verdict', 'N/A').upper()} "
|
||||
f"(confidence: {fc.get('confidence', 0):.2f})\n")
|
||||
f.write(f"💡 {fc.get('explanation', 'N/A')}\n")
|
||||
if fc.get('corrections'):
|
||||
f.write(f"✏️ Correction: {fc['corrections']}\n")
|
||||
f.write("\n")
|
||||
|
||||
if 'questions' in data and data['questions'].get('questions'):
|
||||
f.write("❓ Questions:\n")
|
||||
for i, q in enumerate(data['questions']['questions'], 1):
|
||||
f.write(f"{i}. {q}\n")
|
||||
f.write("\n")
|
||||
|
||||
|
||||
def display_enriched_output(text, timestamp, fact_check=None, questions=None):
|
||||
"""Display transcript with LLM analysis"""
|
||||
print(f"\n[{timestamp}] {text}")
|
||||
|
||||
if fact_check:
|
||||
verdict_emoji = {
|
||||
'factual': '✅',
|
||||
'dubious': '⚠️',
|
||||
'not_factual': '❌',
|
||||
'error': '⚠️'
|
||||
}
|
||||
emoji = verdict_emoji.get(fact_check.get('verdict', 'error'), '❓')
|
||||
|
||||
print(f"\n{emoji} Fact Check: {fact_check.get('verdict', 'N/A').upper()} "
|
||||
f"(confidence: {fact_check.get('confidence', 0):.2f})")
|
||||
print(f"💡 {fact_check.get('explanation', 'N/A')}")
|
||||
|
||||
if fact_check.get('corrections'):
|
||||
print(f"✏️ Correction: {fact_check['corrections']}")
|
||||
|
||||
if questions and questions.get('questions'):
|
||||
print(f"\n❓ Questions:")
|
||||
for i, q in enumerate(questions['questions'], 1):
|
||||
print(f" {i}. {q}")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Real-time transcription of Windows speaker output",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Examples:
|
||||
python transcribe_speakers.py
|
||||
python transcribe_speakers.py --model small --language es --interval 5
|
||||
python transcribe_speakers.py --device "Speakers" --output "meeting.txt"
|
||||
python transcribe_speakers.py --model medium --interval 10 --output transcripts/live.txt
|
||||
"""
|
||||
)
|
||||
|
||||
parser.add_argument("--model", default="base",
|
||||
choices=["tiny", "base", "small", "medium", "large"],
|
||||
help="Whisper model size (default: base)")
|
||||
parser.add_argument("--language", default="en",
|
||||
help="Language code (default: en)")
|
||||
parser.add_argument("--device", metavar="NAME",
|
||||
help="Audio device name (partial match). If not specified, auto-detects")
|
||||
parser.add_argument("--interval", type=float, default=8.0,
|
||||
help="Processing interval in seconds (default: 8.0)")
|
||||
parser.add_argument("--output", "-o", metavar="FILE",
|
||||
help="Save transcript to file (e.g., transcript.txt)")
|
||||
parser.add_argument("--list-devices", action="store_true",
|
||||
help="List all available audio devices and exit")
|
||||
parser.add_argument("--force-cpu", action="store_true",
|
||||
help="Force CPU processing (disable GPU acceleration)")
|
||||
parser.add_argument("--enable-llm", action="store_true",
|
||||
help="Enable LLM analysis (fact-checking and questions)")
|
||||
parser.add_argument("--llm-model", default="gpt-oss:20b",
|
||||
help="Ollama model to use for LLM analysis (default: gpt-oss:20b)")
|
||||
parser.add_argument("--llm-debug", action="store_true",
|
||||
help="Show LLM raw responses for debugging")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.list_devices:
|
||||
list_audio_devices()
|
||||
return
|
||||
|
||||
print("=== Windows Real-Time Audio Transcription ===")
|
||||
print(f"Model: {args.model} | Language: {args.language} | Interval: {args.interval}s")
|
||||
if args.output:
|
||||
print(f"Output: {args.output}")
|
||||
if args.enable_llm:
|
||||
print(f"LLM Analysis: Enabled ({args.llm_model})")
|
||||
|
||||
# Initialize audio capture
|
||||
try:
|
||||
capturer = WindowsLoopbackAudioCapture(
|
||||
device_name=args.device,
|
||||
sample_rate=16000,
|
||||
chunk_size=2048
|
||||
)
|
||||
except RuntimeError as e:
|
||||
print(f"\n❌ Audio Error: {e}")
|
||||
print("\nTo fix this:")
|
||||
print("1. Right-click speaker icon → Sounds → Recording tab")
|
||||
print("2. Right-click in empty area → Show Disabled Devices")
|
||||
print("3. Enable 'Stereo Mix' → Set as Default Device")
|
||||
print("\nAlternative: Install VB-Cable (free) from vb-audio.com")
|
||||
print(" Then use: --device 'CABLE Output'")
|
||||
list_audio_devices()
|
||||
return
|
||||
|
||||
# Initialize transcriber
|
||||
try:
|
||||
transcriber = WhisperStreamTranscriber(
|
||||
model_name=args.model,
|
||||
language=args.language,
|
||||
force_cpu=args.force_cpu
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"\n❌ Model Error: {e}")
|
||||
print("Make sure you installed Whisper correctly")
|
||||
return
|
||||
|
||||
# Initialize LLM analyzer (optional)
|
||||
llm_analyzer = None
|
||||
if args.enable_llm:
|
||||
try:
|
||||
llm_analyzer = LocalLLMAnalyzer(model=args.llm_model, debug=args.llm_debug)
|
||||
except RuntimeError as e:
|
||||
print(f"\n❌ LLM Error: {e}")
|
||||
print("Continuing without LLM analysis...")
|
||||
llm_analyzer = None
|
||||
|
||||
# Main processing loop
|
||||
print(f"\n✅ Started transcription. Press Ctrl+C to stop.\n{'=' * 50}")
|
||||
last_process_time = time.time()
|
||||
total_duration = 0
|
||||
segment_count = 0
|
||||
|
||||
try:
|
||||
while True:
|
||||
# Collect audio
|
||||
chunk = capturer.read_chunk()
|
||||
if chunk is not None:
|
||||
transcriber.add_audio(chunk)
|
||||
total_duration += len(chunk) / 16000
|
||||
|
||||
# Process at intervals
|
||||
current_time = time.time()
|
||||
if current_time - last_process_time >= args.interval:
|
||||
text = transcriber.transcribe_chunk()
|
||||
if text:
|
||||
segment_count += 1
|
||||
timestamp = datetime.now().strftime("%H:%M:%S")
|
||||
|
||||
# LLM Analysis
|
||||
fact_check = None
|
||||
questions = None
|
||||
if llm_analyzer:
|
||||
context = f"Segment {segment_count}"
|
||||
fact_check = llm_analyzer.fact_check(text, context)
|
||||
questions = llm_analyzer.generate_augmenting_questions(text, context)
|
||||
|
||||
# Display output
|
||||
if llm_analyzer:
|
||||
display_enriched_output(text, timestamp, fact_check, questions)
|
||||
else:
|
||||
print(f"[{timestamp}] {text}")
|
||||
|
||||
# Save output
|
||||
if args.output:
|
||||
if llm_analyzer:
|
||||
data = {
|
||||
'timestamp': timestamp,
|
||||
'text': text,
|
||||
'fact_check': fact_check,
|
||||
'questions': questions
|
||||
}
|
||||
save_enriched_transcript(data, args.output)
|
||||
else:
|
||||
save_transcript(text, timestamp, args.output)
|
||||
|
||||
last_process_time = current_time
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print(f"\n{'=' * 50}\n🛑 Stopping transcription...")
|
||||
|
||||
# Cleanup
|
||||
capturer.close()
|
||||
|
||||
# Process remaining audio
|
||||
print("\nProcessing remaining audio...")
|
||||
final_text = transcriber.transcribe_chunk(min_duration=0)
|
||||
if final_text:
|
||||
timestamp = datetime.now().strftime("%H:%M:%S")
|
||||
|
||||
# LLM Analysis for final segment
|
||||
fact_check = None
|
||||
questions = None
|
||||
if llm_analyzer:
|
||||
fact_check = llm_analyzer.fact_check(final_text, "Final segment")
|
||||
questions = llm_analyzer.generate_augmenting_questions(final_text)
|
||||
|
||||
# Display output
|
||||
if llm_analyzer:
|
||||
display_enriched_output(final_text, timestamp, fact_check, questions)
|
||||
else:
|
||||
print(f"[{timestamp}] {final_text}")
|
||||
|
||||
# Save output
|
||||
if args.output:
|
||||
if llm_analyzer:
|
||||
data = {
|
||||
'timestamp': timestamp,
|
||||
'text': final_text,
|
||||
'fact_check': fact_check,
|
||||
'questions': questions
|
||||
}
|
||||
save_enriched_transcript(data, args.output)
|
||||
else:
|
||||
save_transcript(final_text, timestamp, args.output)
|
||||
|
||||
# Summary
|
||||
print(f"\n✅ Complete! Processed {total_duration:.1f}s of audio")
|
||||
print(f" Generated {segment_count} transcript segments")
|
||||
if args.output and os.path.exists(args.output):
|
||||
abs_path = os.path.abspath(args.output)
|
||||
print(f"💾 Transcript saved to: {abs_path}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user