From cde4fca02029cf3552cb63c050d3002bab68828f Mon Sep 17 00:00:00 2001 From: Serghei Cebotari Date: Wed, 20 Sep 2023 13:46:55 +0300 Subject: [PATCH] Solution organize --- .gitignore | 2 + .../.vscode => .vscode}/launch.json | 4 +- .../.vscode => .vscode}/tasks.json | 6 +- Data/misc_sleeves.txt | 7 + Data/rehau_sleeves.txt | 7 + Data/rehau_tpiece.txt | 46 ++ RhSolutions.ML.Builder/.gitignore | 477 ------------------ RhSolutions.ML.Builder/Data/train.tsv | 351 ------------- RhSolutions.ML.Builder/Models/model.zip | Bin 47211 -> 0 bytes RhSolutions.ML.Builder/Program.cs | 47 +- .../RhSolutions.ML.Builder.csproj | 12 +- .../Product.cs | 0 RhSolutions.ML.Lib/RhSolutions.ML.Lib.csproj | 13 + RhSolutions.ML.Lib/RhSolutionsMLBuilder.cs | 42 ++ .../RhSolutions.ML.Tests.csproj | 2 +- RhSolutions.ML.Tests/Tests.cs | 32 +- RhSolutions.ML.sln | 18 +- 17 files changed, 177 insertions(+), 889 deletions(-) rename {RhSolutions.ML.Builder/.vscode => .vscode}/launch.json (84%) rename {RhSolutions.ML.Builder/.vscode => .vscode}/tasks.json (81%) create mode 100644 Data/misc_sleeves.txt create mode 100644 Data/rehau_sleeves.txt create mode 100644 Data/rehau_tpiece.txt delete mode 100644 RhSolutions.ML.Builder/.gitignore delete mode 100644 RhSolutions.ML.Builder/Data/train.tsv delete mode 100644 RhSolutions.ML.Builder/Models/model.zip rename {RhSolutions.ML.Builder => RhSolutions.ML.Lib}/Product.cs (100%) create mode 100644 RhSolutions.ML.Lib/RhSolutions.ML.Lib.csproj create mode 100644 RhSolutions.ML.Lib/RhSolutionsMLBuilder.cs diff --git a/.gitignore b/.gitignore index 154e127..06cba32 100644 --- a/.gitignore +++ b/.gitignore @@ -475,3 +475,5 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk + +Models/ \ No newline at end of file diff --git a/RhSolutions.ML.Builder/.vscode/launch.json b/.vscode/launch.json similarity index 84% rename from RhSolutions.ML.Builder/.vscode/launch.json rename to .vscode/launch.json index 35b44e4..77973cc 100644 --- a/RhSolutions.ML.Builder/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,9 +10,9 @@ "request": "launch", "preLaunchTask": "build", // If you have changed target frameworks, make sure to update the program path. - "program": "${workspaceFolder}/bin/Debug/net7.0/RhSolutions.Classifications.dll", + "program": "${workspaceFolder}/RhSolutions.ML.Builder/bin/Debug/net7.0/RhSolutions.ML.Builder.dll", "args": [], - "cwd": "${workspaceFolder}", + "cwd": "${workspaceFolder}/RhSolutions.ML.Builder", // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console "console": "internalConsole", "stopAtEntry": false diff --git a/RhSolutions.ML.Builder/.vscode/tasks.json b/.vscode/tasks.json similarity index 81% rename from RhSolutions.ML.Builder/.vscode/tasks.json rename to .vscode/tasks.json index a6f0b13..e1d45f0 100644 --- a/RhSolutions.ML.Builder/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -7,7 +7,7 @@ "type": "process", "args": [ "build", - "${workspaceFolder}/RhSolutions.Classifications.csproj", + "${workspaceFolder}/RhSolutions.ML.sln", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], @@ -19,7 +19,7 @@ "type": "process", "args": [ "publish", - "${workspaceFolder}/RhSolutions.Classifications.csproj", + "${workspaceFolder}/RhSolutions.ML.sln", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], @@ -33,7 +33,7 @@ "watch", "run", "--project", - "${workspaceFolder}/RhSolutions.Classifications.csproj" + "${workspaceFolder}/RhSolutions.ML.sln" ], "problemMatcher": "$msCompile" } diff --git a/Data/misc_sleeves.txt b/Data/misc_sleeves.txt new file mode 100644 index 0000000..f879a84 --- /dev/null +++ b/Data/misc_sleeves.txt @@ -0,0 +1,7 @@ +Пресс-втулка 16 Монтажная гильза +Пресс-втулка 20 Монтажная гильза +Пресс-втулка 25 Монтажная гильза +Пресс-втулка 32 Монтажная гильза +Пресс-втулка 40 Монтажная гильза +Пресс-втулка 50 Монтажная гильза +Пресс-втулка 63 Монтажная гильза diff --git a/Data/rehau_sleeves.txt b/Data/rehau_sleeves.txt new file mode 100644 index 0000000..d07e813 --- /dev/null +++ b/Data/rehau_sleeves.txt @@ -0,0 +1,7 @@ +Монтажная гильза 16 PX Монтажная гильза +Монтажная гильза 20 PX Монтажная гильза +Монтажная гильза 25 PX Монтажная гильза +Монтажная гильза 32 PX Монтажная гильза +Монтажная гильза 40 PX Монтажная гильза +Монтажная гильза 50 MX Монтажная гильза +Монтажная гильза 63 MX Монтажная гильза diff --git a/Data/rehau_tpiece.txt b/Data/rehau_tpiece.txt new file mode 100644 index 0000000..a5c52a0 --- /dev/null +++ b/Data/rehau_tpiece.txt @@ -0,0 +1,46 @@ +Тройник равнопроходный 16-16-16 PX Тройник RAUTITAN +Тройник равнопроходный 20-20-20 PX Тройник RAUTITAN +Тройник равнопроходный 25-25-25 PX Тройник RAUTITAN +Тройник равнопроходный 32-32-32 PX Тройник RAUTITAN +Тройник равнопроходный 40-40-40 PX Тройник RAUTITAN +Тройник равнопроходный 50-50-50 RX+ Тройник RAUTITAN +Тройник равнопроходный 63-63-63 RX+ Тройник RAUTITAN +Тройник с уменьшенным боковым проходом 20-16-20 PX Тройник RAUTITAN +Тройник с уменьшенным боковым проходом 25-16-25 PX Тройник RAUTITAN +Тройник с уменьшенным боковым проходом 25-20-25 PX Тройник RAUTITAN +Тройник с уменьшенным боковым проходом 32-16-32 PX Тройник RAUTITAN +Тройник с уменьшенным боковым проходом 32-20-32 PX Тройник RAUTITAN +Тройник с уменьшенным боковым проходом 32-25-32 PX Тройник RAUTITAN +Тройник с уменьшенным боковым проходом 40-20-40 PX Тройник RAUTITAN +Тройник с уменьшенным боковым проходом 40-25-40 PX Тройник RAUTITAN +Тройник с уменьшенным боковым проходом 40-32-40 PX Тройник RAUTITAN +Тройник с уменьшенным боковым проходом 50-20-50 RX Тройник RAUTITAN +Тройник с уменьшенным боковым проходом 50-20-50 RX+ Тройник RAUTITAN +Тройник с уменьшенным боковым проходом 50-25-50 RX+ Тройник RAUTITAN +Тройник с уменьшенным боковым проходом 50-32-50 RX+ Тройник RAUTITAN +Тройник с уменьшенным боковым проходом 50-40-50 RX+ Тройник RAUTITAN +Тройник с уменьшенным боковым проходом 63-25-63 RX+ Тройник RAUTITAN +Тройник с уменьшенным боковым проходом 63-32-63 RX+ Тройник RAUTITAN +Тройник с уменьшенным боковым проходом 63-40-63 RX+ Тройник RAUTITAN +Тройник с уменьшенным боковым проходом 63-50-63 RX+ Тройник RAUTITAN +Тройник с уменьшенным торцевым проходом 20-20-16 PX Тройник RAUTITAN +Тройник с уменьшенным торцевым проходом 25-25-16 PX Тройник RAUTITAN +Тройник с уменьшенным торцевым проходом 25-25-20 PX Тройник RAUTITAN +Тройник с уменьшенным торцевым проходом 32-32-20 PX Тройник RAUTITAN +Тройник с уменьшенным торцевым проходом 32-32-25 PX Тройник RAUTITAN +Тройник с уменьшенным боковым и торцевым проходами 20-16-16 PX Тройник RAUTITAN +Тройник с уменьшенным боковым и торцевым проходами 25-16-16 PX Тройник RAUTITAN +Тройник с уменьшенным боковым и торцевым проходами 25-16-20 PX Тройник RAUTITAN +Тройник с уменьшенным боковым и торцевым проходами 25-20-16 PX Тройник RAUTITAN +Тройник с уменьшенным боковым и торцевым проходами 25-20-20 PX Тройник RAUTITAN +Тройник с уменьшенным боковым и торцевым проходами 32-20-20 PX Тройник RAUTITAN +Тройник с уменьшенным боковым и торцевым проходами 32-20-25 PX Тройник RAUTITAN +Тройник с уменьшенным боковым и торцевым проходами 32-25-20 PX Тройник RAUTITAN +Тройник с уменьшенным боковым и торцевым проходами 32-25-25 PX Тройник RAUTITAN +Тройник с уменьшенным боковым и торцевым проходами 40-32-32 PX Тройник RAUTITAN +Тройник с уменьшенным боковым и торцевым проходами 50-32-40 RX+ Тройник RAUTITAN +Тройник с увеличенным боковым проходом 16-20-16 PX Тройник RAUTITAN +Тройник с увеличенным боковым проходом 16-25-16 PX Тройник RAUTITAN +Тройник с увеличенным боковым проходом 20-25-16 PX Тройник RAUTITAN +Тройник с увеличенным боковым проходом 20-25-20 PX Тройник RAUTITAN +Тройник с увеличенным боковым проходом 25-32-25 PX Тройник RAUTITAN diff --git a/RhSolutions.ML.Builder/.gitignore b/RhSolutions.ML.Builder/.gitignore deleted file mode 100644 index 154e127..0000000 --- a/RhSolutions.ML.Builder/.gitignore +++ /dev/null @@ -1,477 +0,0 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore - -# User-specific files -*.rsuser -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Mono auto generated files -mono_crash.* - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -[Ww][Ii][Nn]32/ -[Aa][Rr][Mm]/ -[Aa][Rr][Mm]64/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ -[Ll]ogs/ - -# Visual Studio 2015/2017 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUnit -*.VisualState.xml -TestResult.xml -nunit-*.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET -project.lock.json -project.fragment.lock.json -artifacts/ - -# Tye -.tye/ - -# ASP.NET Scaffolding -ScaffoldingReadMe.txt - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_h.h -*.ilk -*.meta -*.obj -*.iobj -*.pch -*.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*_wpftmp.csproj -*.log -*.tlog -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Coverlet is a free, cross platform Code Coverage Tool -coverage*.json -coverage*.xml -coverage*.info - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# NuGet Symbol Packages -*.snupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx -*.appxbundle -*.appxupload - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!?*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser -*- [Bb]ackup.rdl -*- [Bb]ackup ([0-9]).rdl -*- [Bb]ackup ([0-9][0-9]).rdl - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat -node_modules/ - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio 6 auto-generated project file (contains which files were open etc.) -*.vbp - -# Visual Studio 6 workspace and project file (working project files containing files to include in project) -*.dsw -*.dsp - -# Visual Studio 6 technical files -*.ncb -*.aps - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# CodeRush personal settings -.cr/personal - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config - -# Tabs Studio -*.tss - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -# OpenCover UI analysis results -OpenCover/ - -# Azure Stream Analytics local run output -ASALocalRun/ - -# MSBuild Binary and Structured Log -*.binlog - -# NVidia Nsight GPU debugger configuration file -*.nvuser - -# MFractors (Xamarin productivity tool) working folder -.mfractor/ - -# Local History for Visual Studio -.localhistory/ - -# Visual Studio History (VSHistory) files -.vshistory/ - -# BeatPulse healthcheck temp database -healthchecksdb - -# Backup folder for Package Reference Convert tool in Visual Studio 2017 -MigrationBackup/ - -# Ionide (cross platform F# VS Code tools) working folder -.ionide/ - -# Fody - auto-generated XML schema -FodyWeavers.xsd - -# VS Code files for those working on multiple tools -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -*.code-workspace - -# Local History for Visual Studio Code -.history/ - -# Windows Installer files from build outputs -*.cab -*.msi -*.msix -*.msm -*.msp - -# JetBrains Rider -*.sln.iml - -## -## Visual studio for Mac -## - - -# globs -Makefile.in -*.userprefs -*.usertasks -config.make -config.status -aclocal.m4 -install-sh -autom4te.cache/ -*.tar.gz -tarballs/ -test-results/ - -# Mac bundle stuff -*.dmg -*.app - -# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore -# General -.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore -# Windows thumbnail cache files -Thumbs.db -ehthumbs.db -ehthumbs_vista.db - -# Dump file -*.stackdump - -# Folder config file -[Dd]esktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Windows Installer files -*.cab -*.msi -*.msix -*.msm -*.msp - -# Windows shortcuts -*.lnk diff --git a/RhSolutions.ML.Builder/Data/train.tsv b/RhSolutions.ML.Builder/Data/train.tsv deleted file mode 100644 index 5d6f4ff..0000000 --- a/RhSolutions.ML.Builder/Data/train.tsv +++ /dev/null @@ -1,351 +0,0 @@ -Name Type -Универсальн.труба RAUTITAN stabil 16,2х2,6 мм, бухта 100 м Труба stabil -Универсальн.труба RAUTITAN stabil 20х2,9 мм, бухта 100 м Труба stabil -Универсальн.труба RAUTITAN stabil 25х3,7 мм, бухта 50 м Труба stabil -Универсальн.труба RAUTITAN stabil 32х4,7 мм, бухта 25 м Труба stabil -Универсальн.труба RAUTITAN stabil 16,2х2,6 мм, прям.отрезки 5м Труба stabil -Универсальн.труба RAUTITAN stabil 20х2,9 мм, прям.отрезки 5м Труба stabil -Универсальн.труба RAUTITAN stabil 25х3,7 мм, прям.отрезки 5м Труба stabil -Универсальн.труба RAUTITAN stabil 32х4,7 мм, прям.отрезки 5м Труба stabil -Универсальн.труба RAUTITAN stabil 40х6,0 мм, прям.отрезки 5м Труба stabil -Унив.труба RAUTITAN flex 16x2,2, бухта 100м Труба flex -Унив.труба RAUTITAN flex 20x2,8, бухта 100м Труба flex -Унив.труба RAUTITAN flex 25x3,5, бухта 50м Труба flex -Унив.труба RAUTITAN flex 32x4,4, бухта 50м Труба flex -Унив.труба RAUTITAN flex 16x2,2, прям.отрезки 6м Труба flex -Унив.труба RAUTITAN flex 20x2,8, прям.отрезки 6м Труба flex -Унив.труба RAUTITAN flex 25x3,5, прям.отрезки 6м Труба flex -Унив.труба RAUTITAN flex 32x4,4, прям.отрезки 6м Труба flex -Унив.труба RAUTITAN flex 40x5,5, прям.отрезки 6м Труба flex -Унив.труба RAUTITAN flex 50x6,9, прям.отрезки 6м Труба flex -Унив.труба RAUTITAN flex 63x8,6, прям.отрезки 6м Труба flex -Унив.труба РЕХАУ FLEX 16x2,2, бухта 100м Труба flex -Унив.труба РЕХАУ FLEX 20x2,8, бухта 100м Труба flex -Унив.труба РЕХАУ FLEX 25x3,5, бухта 50м Труба flex -Унив.труба РЕХАУ FLEX 32x4,4, бухта 50м Труба flex -Унив. труба RAUTITAN pink+ 16х2,2 мм, бухта 120 м Труба pink -Унив. труба RAUTITAN pink+ 16х2,2 мм, прямые отрезки 6 м Труба pink -Унив. труба RAUTITAN pink+ 20х2,8 мм, бухта 120 м Труба pink -Унив. труба RAUTITAN pink+ 20х2,8 мм, прямые отрезки 6 м Труба pink -Унив. труба RAUTITAN pink+ 25х3,5 мм, бухта 50 м Труба pink -Унив. труба RAUTITAN pink+ 25х3,5 мм, прямые отрезки 6 м Труба pink -Унив. труба RAUTITAN pink+ 32х4,4 мм, бухта 50 м Труба pink -Унив. труба RAUTITAN pink+ 32х4,4 мм, прямые отрезки 6 м Труба pink -Унив. труба RAUTITAN pink+ 40х5,5 мм, прямые отрезки 6 м Труба pink -Унив. труба RAUTITAN pink+ 50х6,9 мм, прямые отрезки 6 м Труба pink -Унив. труба RAUTITAN pink+ 63х8,7 мм, прямые отрезки 6 м Труба pink -Отоп. труба RAUTITAN black 16х2,2 мм, бухта 200 м Труба black -Отоп. труба RAUTITAN black 20х2,8 мм, бухта 180 м Труба black -Отоп. труба RAUTITAN black 25х3,5 мм, бухта 100 м Труба black -Отоп.труба РЕХАУ BLACK 16х2,2 мм, бухта 200 м Труба black -Отоп.труба РЕХАУ BLACK 20х2,8 мм, бухта 180 м Труба black -Отоп.труба РЕХАУ BLACK 25х3,5 мм, бухта 100 м Труба black -Фиксирующий желоб для ПЭ-трубы 16/17 Фиксирующий желоб -Фиксирующий желоб для ПЭ-трубы 20 Фиксирующий желоб -Фиксирующий желоб для ПЭ-трубы 25 Фиксирующий желоб -Фиксирующий желоб для ПЭ-трубы 32 Фиксирующий желоб -Фиксирующий желоб для ПЭ-трубы 40 Фиксирующий желоб -Фиксирующий желоб для ПЭ-трубы 50 Фиксирующий желоб -Фиксирующий желоб для ПЭ-трубы 63 Фиксирующий желоб -Монтажная гильза 16 PX Монтажная гильза -Монтажная гильза 20 PX Монтажная гильза -Монтажная гильза 25 PX Монтажная гильза -Монтажная гильза 32 PX Монтажная гильза -Монтажная гильза 40 PX Монтажная гильза -Монтажная гильза 50 MX Монтажная гильза -Монтажная гильза 63 MX Монтажная гильза -Тройник равнопроходный 16-16-16 PX Тройник RAUTITAN -Тройник 16 Тройник RAUTITAN -Тройник 16-16-16 Тройник RAUTITAN -Тройник равнопроходный 20-20-20 PX Тройник RAUTITAN -Тройник 20 Тройник RAUTITAN -Тройник 20-20-20 Тройник RAUTITAN -Тройник равнопроходный 25-25-25 PX Тройник RAUTITAN -Тройник 25 Тройник RAUTITAN -Тройник 25-25-25 Тройник RAUTITAN -Тройник равнопроходный 32-32-32 PX Тройник RAUTITAN -Тройник 32 Тройник RAUTITAN -Тройник 32-32-32 Тройник RAUTITAN -Тройник равнопроходный 40-40-40 PX Тройник RAUTITAN -Тройник 40 Тройник RAUTITAN -Тройник 40-40-40 Тройник RAUTITAN -Тройник равнопроходный 50-50-50 RX+ Тройник RAUTITAN -Тройник 50 Тройник RAUTITAN -Тройник 50-50-50 Тройник RAUTITAN -Тройник равнопроходный 63-63-63 RX+ Тройник RAUTITAN -Тройник 63 Тройник RAUTITAN -Тройник 63-63-63 Тройник RAUTITAN -Проточный настенный угольник 16/16-Rp 1/2 длинный RX+ Проточный угольник -Проточный настенный угольник 20/20-Rp 1/2 длинный RX+ Проточный угольник -Проточный настенный угольник 25/25-Rp 1/2 длинный RX+ Проточный угольник -Проточный настенный угольник 16/16-Rp 1/2 короткий RX+ Проточный угольник -Проточный настенный угольник 20/20-Rp 1/2 короткий RX+ Проточный угольник -Проточный настенный угольник 16/20-Rp 1/2 короткий RX+ Проточный угольник -Проточный настенный угольник 20/16-Rp 1/2 короткий RX+ Проточный угольник -Проточный настенный угольник 25/25-Rp 1/2 короткий RX+ Проточный угольник -Тройник RAUTITAN RX+ с наружной резьбой 16-16-R 1/2 Тройник RAUTITAN резьбовой -Тройник RAUTITAN RX+ с наружной резьбой 20-20-R 1/2 Тройник RAUTITAN резьбовой -Тройник RAUTITAN RX+ с наружной резьбой 20-20-R 3/4 Тройник RAUTITAN резьбовой -Тройник с уменьшенным боковым проходом 20-16-20 PX Тройник RAUTITAN -Тройник с уменьшенным боковым проходом 25-16-25 PX Тройник RAUTITAN -Тройник с уменьшенным боковым проходом 25-20-25 PX Тройник RAUTITAN -Тройник с уменьшенным боковым проходом 32-16-32 PX Тройник RAUTITAN -Тройник с уменьшенным боковым проходом 32-20-32 PX Тройник RAUTITAN -Тройник с уменьшенным боковым проходом 32-25-32 PX Тройник RAUTITAN -Тройник с уменьшенным боковым проходом 40-20-40 PX Тройник RAUTITAN -Тройник с уменьшенным боковым проходом 40-25-40 PX Тройник RAUTITAN -Тройник с уменьшенным боковым проходом 40-32-40 PX Тройник RAUTITAN -Тройник с уменьшенным боковым проходом 50-20-50 RX+ Тройник RAUTITAN -Тройник с уменьшенным боковым проходом 50-25-50 RX+ Тройник RAUTITAN -Тройник с уменьшенным боковым проходом 50-32-50 RX+ Тройник RAUTITAN -Тройник с уменьшенным боковым проходом 50-40-50 RX+ Тройник RAUTITAN -Тройник с уменьшенным боковым проходом 63-25-63 RX+ Тройник RAUTITAN -Тройник с уменьшенным боковым проходом 63-32-63 RX+ Тройник RAUTITAN -Тройник с уменьшенным боковым проходом 63-40-63 RX+ Тройник RAUTITAN -Тройник с уменьшенным боковым проходом 63-50-63 RX+ Тройник RAUTITAN -Тройник с уменьшенным торцевым проходом 20-20-16 PX Тройник RAUTITAN -Тройник с уменьшенным торцевым проходом 25-25-16 PX Тройник RAUTITAN -Тройник с уменьшенным торцевым проходом 25-25-20 PX Тройник RAUTITAN -Тройник с уменьшенным торцевым проходом 32-32-20 PX Тройник RAUTITAN -Тройник с уменьшенным торцевым проходом 32-32-25 PX Тройник RAUTITAN -Тройник с уменьшенным боковым и торцевым проходами 20-16-16 PX Тройник RAUTITAN -Тройник с уменьшенным боковым и торцевым проходами 25-16-16 PX Тройник RAUTITAN -Тройник с уменьшенным боковым и торцевым проходами 25-16-20 PX Тройник RAUTITAN -Тройник с уменьшенным боковым и торцевым проходами 25-20-16 PX Тройник RAUTITAN -Тройник с уменьшенным боковым и торцевым проходами 25-20-20 PX Тройник RAUTITAN -Тройник с уменьшенным боковым и торцевым проходами 32-20-20 PX Тройник RAUTITAN -Тройник с уменьшенным боковым и торцевым проходами 32-20-25 PX Тройник RAUTITAN -Тройник с уменьшенным боковым и торцевым проходами 32-25-20 PX Тройник RAUTITAN -Тройник с уменьшенным боковым и торцевым проходами 32-25-25 PX Тройник RAUTITAN -Тройник с уменьшенным боковым и торцевым проходами 40-32-32 PX Тройник RAUTITAN -Тройник с уменьшенным боковым и торцевым проходами 50-32-40 RX+ Тройник RAUTITAN -Тройник с увеличенным боковым проходом 16-20-16 PX Тройник RAUTITAN -Тройник с увеличенным боковым проходом 16-25-16 PX Тройник RAUTITAN -Тройник с увеличенным боковым проходом 20-25-16 PX Тройник RAUTITAN -Тройник с увеличенным боковым проходом 20-25-20 PX Тройник RAUTITAN -Тройник с увеличенным боковым проходом 25-32-25 PX Тройник RAUTITAN -Тройник настенный с внутренней резьбой 16-Rp1/2-16 RX+ Тройник RAUTITAN резьбовой -Тройник настенный с внутренней резьбой 20-Rp1/2-16 RX+ Тройник RAUTITAN резьбовой -Тройник настенный с внутренней резьбой 20-Rp1/2-20 RX+ Тройник RAUTITAN резьбовой -Тройник с внутр. резьбой на боков. проходе 25-Rp 1/2-25 RX+ Тройник RAUTITAN резьбовой -Тройник с внутр. резьбой на боков. проходе 25-Rp 3/4-25 RX+ Тройник RAUTITAN резьбовой -Тройник с внутр. резьбой на боков. проходе 32-Rp 3/4-25 RX+ Тройник RAUTITAN резьбовой -Тройник с внутр. резьбой на боков. проходе 32-Rp 3/4-32 RX+ Тройник RAUTITAN резьбовой -Тройник с внутр. резьбой на боков. проходе 32-Rp 1-32 RX+ Тройник RAUTITAN резьбовой -Тройник с внутр. резьбой на боков. проходе 40-Rp 1-40 RX+ Тройник RAUTITAN резьбовой -Тройник с внутр. резьбой на боков. проходе 50-Rp 1-50 RX+ Тройник RAUTITAN резьбовой -Муфта соединительная равнопроходная 16 PX Муфта соединительная -Муфта соединительная равнопроходная 20 PX Муфта соединительная -Муфта соединительная равнопроходная 25 PX Муфта соединительная -Муфта соединительная равнопроходная 32 PX Муфта соединительная -Муфта соединительная равнопроходная 40 PX Муфта соединительная -Муфта соединительная равнопроходная 50 RХ+ Муфта соединительная -Муфта соединительная равнопроходная 63 RХ + Муфта соединительная -Муфта соединительная переходная 20-16 PX Муфта соединительная -Муфта соединительная переходная 25-16 PX Муфта соединительная -Муфта соединительная переходная 25-20 PX Муфта соединительная -Муфта соединительная переходная 32-25 PX Муфта соединительная -Муфта соединительная переходная 40-32 PX Муфта соединительная -Муфта соединительная переходная 40-25 RX+ Муфта соединительная -Муфта соединительная переходная 50-32 RX+ Муфта соединительная -Муфта соединительная переходная 50-40 RX+ Муфта соединительная -Муфта соединительная переходная 63-50 RX+ Муфта соединительная -Переходник с наружной резьбой 16-R 1/2 RX+ Переходник на наружную резьбу -Переходник с наружной резьбой 16-R 3/4 RX+ Переходник на наружную резьбу -Переходник с наружной резьбой 16-R 1 RX+ Переходник на наружную резьбу -Переходник с наружной резьбой 20-R 1/2 RX+ Переходник на наружную резьбу -Переходник с наружной резьбой 20-R 3/4 RX+ Переходник на наружную резьбу -Переходник с наружной резьбой 20-R 1 RX+ Переходник на наружную резьбу -Переходник с наружной резьбой 25-R 1/2 RX+ Переходник на наружную резьбу -Переходник с наружной резьбой 25-R 3/4 RX+ Переходник на наружную резьбу -Переходник с наружной резьбой 25-R 1 RX+ Переходник на наружную резьбу -Переходник с наружной резьбой 32-R 3/4 RX+ Переходник на наружную резьбу -Переходник с наружной резьбой 32-R 1 RX+ Переходник на наружную резьбу -Переходник с наружной резьбой 32-R 1 1/4 RX+ Переходник на наружную резьбу -Переходник с наружной резьбой 40-R 1 1/4 RX+ Переходник на наружную резьбу -Переходник с наружной резьбой 50-R 1 1/4 RX+ Переходник на наружную резьбу -Переходник с наружной резьбой 50-R 1 1/2 RX+ Переходник на наружную резьбу -Переходник с наружной резьбой 63-R 2 RX+ Переходник на наружную резьбу -Переходник с внутренней резьбой 16-Rp 1/2 RX+ Переходник на внутреннюю резьбу -Переходник с внутренней резьбой 20-Rp 1/2 RX+ Переходник на внутреннюю резьбу -Переходник с внутренней резьбой 20-Rp 3/4 RX+ Переходник на внутреннюю резьбу -Переходник с внутренней резьбой 25-Rp 1/2 RX+ Переходник на внутреннюю резьбу -Переходник с внутренней резьбой 25-Rp 3/4 RX+ Переходник на внутреннюю резьбу -Переходник с внутренней резьбой 25-Rp 1 RX+ Переходник на внутреннюю резьбу -Переходник с внутренней резьбой 32-Rp 3/4 RX+ Переходник на внутреннюю резьбу -Переходник с внутренней резьбой 32-Rр 1 RX+ Переходник на внутреннюю резьбу -Переходник с внутренней резьбой 40-Rр 1 1/4 RX+ Переходник на внутреннюю резьбу -Переходник с накидной гайкой 16-G 1/2 RX+ Переходник на накидную гайку -Переходник с накидной гайкой 16-G 3/4 RX+ Переходник на накидную гайку -Переходник с накидной гайкой 20-G 1/2 RX+ Переходник на накидную гайку -Переходник с накидной гайкой 20-G 3/4 RX+ Переходник на накидную гайку -Переходник с накидной гайкой 25-G 3/4 RX+ Переходник на накидную гайку -Переходник с накидной гайкой 25-G 1 RX+ Переходник на накидную гайку -Переходник с накидной гайкой 32-G 1 RX+ Переходник на накидную гайку -Переходник с накидной гайкой 32-G 1 1/4 RX+ Переходник на накидную гайку -Переходник с накидной гайкой 32-G 1 1/2 RX+ Переходник на накидную гайку -Переходник с накидной гайкой 40-G 1 1/2 RX+ Переходник на накидную гайку -Переходник с накидной гайкой 50-G 1 3/4 RX+ Переходник на накидную гайку -Переходник с накидной гайкой 63-G 2 3/8 RX+ Переходник на накидную гайку -Переходник на евроконус 16-G 3/4 Переходник на евроконус -Переходник на евроконус 20-G 3/4 Переходник на евроконус -Угольник 90°, 50 RX+ Угольник -Угольник 90°, 63 RX+ Угольник -Угольник 90°, 16 PX Угольник -Угольник 90°, 20 PX Угольник -Угольник 90°, 25 PX Угольник -Угольник 90°, 32 PX Угольник -Угольник 90°, 40 PX Угольник -Угольник 45°, 50 RX+ Угольник -Угольник 45°, 63 RX+ Угольник -Угольник 45°, 20 PX Угольник -Угольник 45°, 25 PX Угольник -Угольник 45°, 32 PX Угольник -Угольник 45°, 40 PX Угольник -Фиксатор поворота с кольцами 90°, 16 Фиксатор поворота -Фиксатор поворота с кольцами 90°, 20 Фиксатор поворота -Фиксатор поворота с кольцами 90°, 25 Фиксатор поворота -Фиксатор поворота с кольцами 90°, 32 Фиксатор поворота -Фиксатор поворота с кольцами 45°, 16 Фиксатор поворота -Фиксатор поворота с кольцами 45°, 20 Фиксатор поворота -Фиксатор поворота с кольцами 45°, 25 Фиксатор поворота -Фиксатор поворота с кольцами 45°, 32 Фиксатор поворота -Угольник-переходник с наружной резьбой 16-R 1/2 RX+ Угольник с наружной резьбой -Угольник-переходник с наружной резьбой 20-R 1/2 RX+ Угольник с наружной резьбой -Угольник-переходник с наружной резьбой 20-R 3/4 RX+ Угольник с наружной резьбой -Угольник-переходник с наружной резьбой 25-R 3/4 RX+ Угольник с наружной резьбой -Угольник-переходник с наружной резьбой 32-R 3/4 RX+ Угольник с наружной резьбой -Угольник-переходник с наружной резьбой 32-R 1 RX+ Угольник с наружной резьбой -Угольник-переходник с внутренней резьбой 16-Rp 1/2 RX+ Угольник с внутренней резьбой -Угольник-переходник с внутренней резьбой 16-Rp 3/4 RX+ Угольник с внутренней резьбой -Угольник-переходник с внутренней резьбой 20-Rp 1/2 RX+ Угольник с внутренней резьбой -Угольник-переходник с внутренней резьбой 20-Rp 3/4 RX+ Угольник с внутренней резьбой -Угольник-переходник с внутренней резьбой 25-Rp 1 RX+ Угольник с внутренней резьбой -Угольник настенный с внутр. резьбой 16-Rp 1/2 RX+ Угольник с внутренней резьбой -Угольник настенный с внутр. резьбой 20-Rp 1/2 RX+ Угольник с внутренней резьбой -Угольник настенный с внутр. резьбой 20-Rp 3/4 RX+ Угольник с внутренней резьбой -Угольник настенный с внутр. резьбой 25-Rp 3/4 RX+ Угольник с внутренней резьбой -Угольник настенный с длинным патрубком, внутр. резьба 16-Rp 1/2 RX+ Угольник с внутренней резьбой -Угольник настенный с длинным патрубком, внутр. резьба 20-Rp 1/2 RX+ Угольник с внутренней резьбой -Угольник настенный с наружной резьбой 16-R 1/2 RX+ Угольник с наружной резьбой -Угольник настенный с наружной резьбой 20-R 1/2 RX+ Угольник с наружной резьбой -Угольник настенный с наружной резьбой 20-R 3/4 RX+ Угольник с наружной резьбой -Угольник настенный с внутр. резьбой 16-Rp 1/2 длинный, 59 мм RX+ Угольник с внутренней резьбой -Угольник настенный с внутр. резьбой 20-Rp 1/2 длинный, 59 мм RX+ Угольник с внутренней резьбой -Угольник настенный с внутр. резьбой 16-Rp 1/2 длинный, 70 мм RX+ Угольник с внутренней резьбой -Угольник настенный с внутренней резьбой 20-Rp1/2 70мм RX+ Угольник с внутренней резьбой -Кронштейн, тип O 100 Кронштейн -Кронштейн, тип O 75 / 150 Кронштейн -Кронштейн, тип D в сборе Кронштейн -Кронштейн, тип Z 30 Кронштейн -Кронштейн, тип Z 42 Кронштейн -Кронштейн, тип Е Кронштейн -Кронштейн 75 / 150 Кронштейн -Распределительный коллектор G1 2 отвода G 3/4 Сборный коллектор -Распределительный коллектор G1 3 отвода G 3/4 Сборный коллектор -Распределительный коллектор G1 4 отвода G 3/4 Сборный коллектор -Трубка из. нерж. стали для подкл. радиатора, Г-образная 16/250 Трубка для радиатора -Трубка из. нерж. стали для подкл. радиатора, Г-образная 16/500 Трубка для радиатора -Трубка из. нерж. стали для подкл. радиатора, Г-образная 16/1000 Трубка для радиатора -Трубка из. нерж. стали для подкл. радиатора, Г-образная 20/250 Трубка для радиатора -Трубка из. нерж. стали для подкл. радиатора, Г-образная 20/500 Трубка для радиатора -Трубка из. нерж. стали для подкл. радиатора, Г-образная 20/1000 Трубка для радиатора -Комплект трубок из. нерж. стали для подкл. радиатора, Г-образ 16/250 Трубка для радиатора -Комплект трубок из. нерж. стали для подкл. радиатора, Г-образ 20/250 Трубка для радиатора -Трубка из. нерж. стали для подкл. радиатора, Т-образная 16/250 Трубка для радиатора -Трубка из. нерж. стали для подкл. радиатора, Т-образная 16/500 Трубка для радиатора -Трубка из. нерж. стали для подкл. радиатора, Т-образная 16/1000 Трубка для радиатора -Трубка из. нерж. стали для подкл. радиатора, Т-образная 20/250 Трубка для радиатора -Трубка из. нерж. стали для подкл. радиатора, Т-образная 20/500 Трубка для радиатора -Трубка из. нерж. стали для подкл. радиатора, Т-образная 20/1000 Трубка для радиатора -К-т двух резьбозажим. нипелей с нар.резьбой 1/2х3/4 (латунь) Ниппель -Резьбозажимное соединение для металлической трубки G 3/4 -15 Резьбозажимное для трубки -Пара шаровых кранов с соед. нип. G 1/2xG 3/4, прямой (никелирован.) Краны -Пара шаровых кранов с соед. нип. G 1/2xG 3/4, угловой (никелирован.) Краны -Распределительный коллектор HLV на 2 группы нерж. сталь Коллектор -Распределительный коллектор HLV на 3 групп нерж. сталь Коллектор -Распределительный коллектор HLV на 4 группы нерж. сталь Коллектор -Распределительный коллектор HLV на 5 групп нерж. сталь Коллектор -Распределительный коллектор HLV на 6 групп нерж. сталь Коллектор -Распределительный коллектор HLV на 7 групп нерж. сталь Коллектор -Распределительный коллектор HLV на 8 групп нерж. сталь Коллектор -Распределительный коллектор HLV на 9 групп нерж. сталь Коллектор -Распределительный коллектор HLV на 10 групп нерж. сталь Коллектор -Распределительный коллектор HLV на 11 групп нерж. сталь Коллектор -Распределительный коллектор HLV на 12 групп нерж. сталь Коллектор -Резьбозажимное соединение flex/pink 16х2,2xG3/4 Резьбозажимное для трубы -Резьбозажимное соединение stabil 16,2x2,6xG3/4 Резьбозажимное для трубы -Резьбозажимное соединение stabil 20x2,9xG3/4 Резьбозажимное для трубы -"Комплект двух прямых никелирован. шаровых кранов G1"" для коллекторов " Краны -"Комплект двух угловых никелирован. шаровых кранов G1"" для коллекторов " Краны -Шкаф коллекторный, встраиваемый, тип UP 110/450 белый Шкаф -Шкаф коллекторный, встраиваемый, тип UP 110/550, белый Шкаф -Шкаф коллекторный, встраиваемый, тип UP 110/750, белый Шкаф -Шкаф коллекторный, встраиваемый, тип UP 110/950, белый Шкаф -Шкаф коллекторный, встраиваемый, тип UP 110/1150, белый Шкаф -Шкаф коллекторный, встраиваемый, тип UP 110/1300, белый Шкаф -Шкаф коллекторный, приставной, тип AP 130/500 белый Шкаф -Шкаф коллекторный, приставной, тип AP 130/605, белый Шкаф -Шкаф коллекторный, приставной, тип AP 130/805, белый Шкаф -Шкаф коллекторный, приставной, тип AP 130/1005, белый Шкаф -Шкаф коллекторный, приставной, тип AP 130/1205, белый Шкаф -Шкаф коллекторный, приставной, тип AP 130/1353, белый Шкаф -Шкаф коллекторный, встраиваемый, тип UP 75/550 , белый Шкаф -Шкаф коллекторный, встраиваемый, тип UP 75/750, белый Шкаф -Шкаф коллекторный, встраиваемый, тип UP 75/950, белый Шкаф -Шкаф коллекторный, встраиваемый, тип UP 75/1150, белый Шкаф -Крюк с дюбелем для 1 трубы Крюк -Двойной крюк с дюбелем для 2-х труб Крюк -Двойной крюк с дюбелем для 2-х труб в изоляции Крюк -Фиксатор поворота трубы 16/17/90°, без колец (оцинк. сталь) Фиксатор поворота -Фиксатор поворота трубы 20/90°, без колец (оцинк. сталь) Фиксатор поворота -Фиксатор поворота трубы 25/90°, без колец (оцинк. сталь) Фиксатор поворота -Фиксатор поворота трубы 32/90°, с кольцами (оцинк. сталь) Фиксатор поворота -Фиксатор поворота трубы 16/17/45°, без колец (оцинк. сталь) Фиксатор поворота -Фиксатор поворота трубы 20/45°, без колец (оцинк. сталь) Фиксатор поворота -Фиксатор поворота трубы 25/45°, без колец (оцинк. сталь) Фиксатор поворота -Фиксатор поворота трубы 32/45°, с кольцами (оцинк. сталь) Фиксатор поворота -Пресс-втулка 16 Монтажная гильза -Пресс-втулка 20 Монтажная гильза -Пресс-втулка 25 Монтажная гильза -Пресс-втулка 32 Монтажная гильза -Пресс-втулка 40 Монтажная гильза -Пресс-втулка 50 Монтажная гильза -Пресс-втулка 63 Монтажная гильза -Тройник 40/40/45° Тройник RAUPIANO -Тройник 40/40/87° Тройник RAUPIANO -Тройник 50/40/45° Тройник RAUPIANO -Тройник 50/40/87° Тройник RAUPIANO -Тройник 50/50/45° Тройник RAUPIANO -Тройник 50/50/87° Тройник RAUPIANO -Тройник 75/50/45° Тройник RAUPIANO -Тройник 75/50/87° Тройник RAUPIANO -Тройник 75/75/45° Тройник RAUPIANO -Тройник 75/75/87° Тройник RAUPIANO -Тройник 90/50/45° Тройник RAUPIANO -Тройник 90/50/87° Тройник RAUPIANO -Тройник 90/75/45° Тройник RAUPIANO -Тройник 90/75/87° Тройник RAUPIANO -Тройник 90/90/45° Тройник RAUPIANO -Тройник 90/90/87° max flow (гидравл. оптимизированный радиус изгиба) Тройник RAUPIANO -Тройник 110/50/45° Тройник RAUPIANO -Тройник 110/50/87° Тройник RAUPIANO -Тройник 110/75/45° Тройник RAUPIANO -Тройник 110/75/87° Тройник RAUPIANO -Тройник 110/90/45° Тройник RAUPIANO -Тройник 110/90/87° Тройник RAUPIANO -Тройник 110/110/45° Тройник RAUPIANO -Тройник 110/110/87° max flow (гидравл. оптимизированный радиус изгиба) Тройник RAUPIANO -Тройник 125/110/45° Тройник RAUPIANO -Тройник 125/110/87° Тройник RAUPIANO -Тройник 125/125/45° Тройник RAUPIANO -Тройник 125/125/87° Тройник RAUPIANO -Тройник 160/110/45° Тройник RAUPIANO -Тройник 160/110/87° Тройник RAUPIANO -Тройник 160/125/45° Тройник RAUPIANO -Тройник 160/125/87° Тройник RAUPIANO -Тройник 160/160/45° Тройник RAUPIANO -Тройник 160/160/87° Тройник RAUPIANO -Тройник 200/160/45° Тройник RAUPIANO -Тройник 200/160/87° Тройник RAUPIANO -Тройник 200/200/45° Тройник RAUPIANO diff --git a/RhSolutions.ML.Builder/Models/model.zip b/RhSolutions.ML.Builder/Models/model.zip deleted file mode 100644 index 7b7bb6985368c818c40f786202a0884289d7f497..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47211 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
    6SY5_87jod_gu5xdEfC0Z>W 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 diff --git a/RhSolutions.ML.Builder/Program.cs b/RhSolutions.ML.Builder/Program.cs index 898e872..ffb62e3 100644 --- a/RhSolutions.ML.Builder/Program.cs +++ b/RhSolutions.ML.Builder/Program.cs @@ -1,42 +1,11 @@ -using Microsoft.ML; +using RhSolutions.ML.Lib; -namespace RhSolutions.ML.Builder +try { - public class Program - { - private static string _appPath = Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]) ?? "."; - private static MLContext _mlContext = new MLContext(seed: 0); - public static void Main() - { - var _trainDataView = _mlContext.Data.LoadFromTextFile( - Path.Combine(_appPath, "..", "..", "..", "Data", "train.tsv"), hasHeader: true); - var pipeline = ProcessData(); - BuildAndTrainModel(_trainDataView, pipeline, out ITransformer trainedModel); - SaveModelAsFile(_mlContext, _trainDataView.Schema, trainedModel); - } - - private static IEstimator ProcessData() - { - var pipeline = _mlContext.Transforms.Conversion.MapValueToKey(inputColumnName: "Type", outputColumnName: "Label") - .Append(_mlContext.Transforms.Text.FeaturizeText(inputColumnName: "Name", outputColumnName: "NameFeaturized")) - .Append(_mlContext.Transforms.Concatenate("Features", "NameFeaturized")) - .AppendCacheCheckpoint(_mlContext); - return pipeline; - } - - private static IEstimator BuildAndTrainModel(IDataView trainingDataView, IEstimator pipeline, out ITransformer trainedModel) - { - var trainingPipeline = pipeline.Append(_mlContext.MulticlassClassification.Trainers.SdcaMaximumEntropy("Label", "Features")) - .Append(_mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel")); - - trainedModel = trainingPipeline.Fit(trainingDataView); - return trainingPipeline; - } - - private static void SaveModelAsFile(MLContext mlContext, DataViewSchema trainingDataViewSchema, ITransformer model) - { - mlContext.Model.Save(model, trainingDataViewSchema, - Path.Combine(_appPath, "..", "..", "..", "Models", "model.zip")); - } - } + RhSolutionsMLBuilder.RebuildModel(); + Console.WriteLine("Model built"); +} +catch (Exception ex) +{ + Console.WriteLine(ex.Message); } \ No newline at end of file diff --git a/RhSolutions.ML.Builder/RhSolutions.ML.Builder.csproj b/RhSolutions.ML.Builder/RhSolutions.ML.Builder.csproj index 75b0dcc..e034a8f 100644 --- a/RhSolutions.ML.Builder/RhSolutions.ML.Builder.csproj +++ b/RhSolutions.ML.Builder/RhSolutions.ML.Builder.csproj @@ -1,5 +1,9 @@ + + + + Exe net7.0 @@ -7,12 +11,4 @@ enable - - - - - - PreserveNewest - - diff --git a/RhSolutions.ML.Builder/Product.cs b/RhSolutions.ML.Lib/Product.cs similarity index 100% rename from RhSolutions.ML.Builder/Product.cs rename to RhSolutions.ML.Lib/Product.cs diff --git a/RhSolutions.ML.Lib/RhSolutions.ML.Lib.csproj b/RhSolutions.ML.Lib/RhSolutions.ML.Lib.csproj new file mode 100644 index 0000000..928fc99 --- /dev/null +++ b/RhSolutions.ML.Lib/RhSolutions.ML.Lib.csproj @@ -0,0 +1,13 @@ + + + + net7.0 + enable + enable + + + + + + + diff --git a/RhSolutions.ML.Lib/RhSolutionsMLBuilder.cs b/RhSolutions.ML.Lib/RhSolutionsMLBuilder.cs new file mode 100644 index 0000000..be2e2a6 --- /dev/null +++ b/RhSolutions.ML.Lib/RhSolutionsMLBuilder.cs @@ -0,0 +1,42 @@ +using Microsoft.ML; + +namespace RhSolutions.ML.Lib; + +public class RhSolutionsMLBuilder +{ + private static string _appPath = Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]) ?? "."; + + private static MLContext _mlContext = new MLContext(seed: 0); + + public static void RebuildModel() + { + var _trainDataView = _mlContext.Data.LoadFromTextFile( + Path.Combine(_appPath, "..", "..", "..", "..", "Data", "*"), hasHeader: false); + var pipeline = ProcessData(); + BuildAndTrainModel(_trainDataView, pipeline, out ITransformer trainedModel); + SaveModelAsFile(_mlContext, _trainDataView.Schema, trainedModel); + } + private static IEstimator ProcessData() + { + var pipeline = _mlContext.Transforms.Conversion.MapValueToKey(inputColumnName: "Type", outputColumnName: "Label") + .Append(_mlContext.Transforms.Text.FeaturizeText(inputColumnName: "Name", outputColumnName: "NameFeaturized")) + .Append(_mlContext.Transforms.Concatenate("Features", "NameFeaturized")) + .AppendCacheCheckpoint(_mlContext); + return pipeline; + } + + private static IEstimator BuildAndTrainModel(IDataView trainingDataView, IEstimator pipeline, out ITransformer trainedModel) + { + var trainingPipeline = pipeline.Append(_mlContext.MulticlassClassification.Trainers.SdcaMaximumEntropy("Label", "Features")) + .Append(_mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel")); + + trainedModel = trainingPipeline.Fit(trainingDataView); + return trainingPipeline; + } + + private static void SaveModelAsFile(MLContext mlContext, DataViewSchema trainingDataViewSchema, ITransformer model) + { + mlContext.Model.Save(model, trainingDataViewSchema, + Path.Combine(_appPath, "..", "..", "..", "..", "Models", "model.zip")); + } +} diff --git a/RhSolutions.ML.Tests/RhSolutions.ML.Tests.csproj b/RhSolutions.ML.Tests/RhSolutions.ML.Tests.csproj index 697d9a0..c37ac53 100644 --- a/RhSolutions.ML.Tests/RhSolutions.ML.Tests.csproj +++ b/RhSolutions.ML.Tests/RhSolutions.ML.Tests.csproj @@ -19,7 +19,7 @@ - + diff --git a/RhSolutions.ML.Tests/Tests.cs b/RhSolutions.ML.Tests/Tests.cs index e8203a0..0349ddb 100644 --- a/RhSolutions.ML.Tests/Tests.cs +++ b/RhSolutions.ML.Tests/Tests.cs @@ -3,8 +3,7 @@ namespace RhSolutions.ML.Tests; public class Tests { private static string _appPath = Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]) ?? "."; - private static string _dataPath = Path.Combine(_appPath, "..", "..", "..", ".." - ,"RhSolutions.ML.Builder" , "Models", "model.zip"); + private static string _dataPath = Path.Combine(_appPath, "..", "..", "..", "..", "Models", "model.zip"); private MLContext _mlContext; private PredictionEngine _predEngine; @@ -56,4 +55,33 @@ public class Tests var prediction = _predEngine.Predict(p); Assert.That(prediction.Type, Is.EqualTo("Тройник RAUPIANO")); } + + [TestCase("Муфта соединительная равнопроходная 16 PX")] + [TestCase("Муфта 16")] + [TestCase("Переход 20-16")] + [TestCase("Переходник 20-16")] + public void CouplingTest(string name) + { + Product p = new() + { + Name = name + }; + var prediction = _predEngine.Predict(p); + Assert.That(prediction.Type, Is.EqualTo("Муфта соединительная")); + } + + [TestCase("Переходник с наружной резьбой 20-R 3/4 RX+")] + [TestCase("Переходник 16 1/2 НР")] + [TestCase("ПНР 16")] + [TestCase("Переход НР 16 1/2")] + [TestCase("Муфта НР 16 1/2")] + public void AdapterExternalTest(string name) + { + Product p = new() + { + Name = name + }; + var prediction = _predEngine.Predict(p); + Assert.That(prediction.Type, Is.EqualTo("Переходник на наружную резьбу")); + } } \ No newline at end of file diff --git a/RhSolutions.ML.sln b/RhSolutions.ML.sln index ec0bbab..95b927c 100644 --- a/RhSolutions.ML.sln +++ b/RhSolutions.ML.sln @@ -3,24 +3,30 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.6.33815.320 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RhSolutions.ML.Builder", "RhSolutions.ML.Builder\RhSolutions.ML.Builder.csproj", "{0ADAA6BD-87CB-4F92-83B2-6C3788634F31}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RhSolutions.ML.Tests", "RhSolutions.ML.Tests\RhSolutions.ML.Tests.csproj", "{E21FC75D-A7E6-4BC2-AFC5-9E36715240FA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RhSolutions.ML.Lib", "RhSolutions.ML.Lib\RhSolutions.ML.Lib.csproj", "{36239F13-0F62-4AD7-B0AF-FA24E8101FA7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RhSolutions.ML.Builder", "RhSolutions.ML.Builder\RhSolutions.ML.Builder.csproj", "{13C69C4E-6A1A-4646-8F2B-9C058E1B0FAD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0ADAA6BD-87CB-4F92-83B2-6C3788634F31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0ADAA6BD-87CB-4F92-83B2-6C3788634F31}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0ADAA6BD-87CB-4F92-83B2-6C3788634F31}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0ADAA6BD-87CB-4F92-83B2-6C3788634F31}.Release|Any CPU.Build.0 = Release|Any CPU {E21FC75D-A7E6-4BC2-AFC5-9E36715240FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E21FC75D-A7E6-4BC2-AFC5-9E36715240FA}.Debug|Any CPU.Build.0 = Debug|Any CPU {E21FC75D-A7E6-4BC2-AFC5-9E36715240FA}.Release|Any CPU.ActiveCfg = Release|Any CPU {E21FC75D-A7E6-4BC2-AFC5-9E36715240FA}.Release|Any CPU.Build.0 = Release|Any CPU + {36239F13-0F62-4AD7-B0AF-FA24E8101FA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {36239F13-0F62-4AD7-B0AF-FA24E8101FA7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {36239F13-0F62-4AD7-B0AF-FA24E8101FA7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {36239F13-0F62-4AD7-B0AF-FA24E8101FA7}.Release|Any CPU.Build.0 = Release|Any CPU + {13C69C4E-6A1A-4646-8F2B-9C058E1B0FAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {13C69C4E-6A1A-4646-8F2B-9C058E1B0FAD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {13C69C4E-6A1A-4646-8F2B-9C058E1B0FAD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {13C69C4E-6A1A-4646-8F2B-9C058E1B0FAD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE