2024-08-11 20:32:36 +02:00
using Flowframes.Data ;
using Flowframes.IO ;
2021-08-23 16:50:18 +02:00
using Flowframes.MiscUtils ;
2022-07-24 22:30:30 +02:00
using Flowframes.Ui ;
2021-08-23 16:50:18 +02:00
using System.Diagnostics ;
using System.IO ;
using System.Threading.Tasks ;
namespace Flowframes.Os
{
class Python
{
2024-08-15 11:34:36 +02:00
public static bool DisablePython = false ;
2021-08-23 16:50:18 +02:00
static bool hasCheckedSysPy = false ;
static bool sysPyInstalled = false ;
public static string compactOutput ;
public static async Task CheckCompression ( )
{
2024-08-15 11:34:36 +02:00
if ( DisablePython | | ! HasEmbeddedPyFolder ( ) | | ( Config . Get ( Config . Key . compressedPyVersion ) = = Updater . GetInstalledVer ( ) . ToString ( ) ) )
2024-08-11 20:47:36 +02:00
return ;
Program . mainForm . SetWorking ( true , false ) ;
Stopwatch sw = new Stopwatch ( ) ;
sw . Restart ( ) ;
try
2021-08-23 16:50:18 +02:00
{
2024-08-11 20:47:36 +02:00
bool shownPatienceMsg = false ;
Logger . Log ( "Compressing python runtime. This only needs to be done once." ) ;
compactOutput = "" ;
Process compact = OsUtils . NewProcess ( true ) ;
compact . StartInfo . Arguments = $"/C compact /C /S:{GetPyFolder().Wrap()} /EXE:LZX" ;
compact . OutputDataReceived + = new DataReceivedEventHandler ( CompactOutputHandler ) ;
compact . ErrorDataReceived + = new DataReceivedEventHandler ( CompactOutputHandler ) ;
compact . Start ( ) ;
compact . BeginOutputReadLine ( ) ;
compact . BeginErrorReadLine ( ) ;
while ( ! compact . HasExited )
2021-08-23 16:50:18 +02:00
{
2024-08-11 20:47:36 +02:00
await Task . Delay ( 500 ) ;
2022-05-31 11:09:56 +02:00
2024-08-11 20:47:36 +02:00
if ( sw . ElapsedMilliseconds > 10000 )
2021-08-23 16:50:18 +02:00
{
2024-08-11 20:47:36 +02:00
Logger . Log ( $"This can take up to a few minutes, but only needs to be done once. (Elapsed: {FormatUtils.Time(sw.Elapsed)})" , false , shownPatienceMsg ) ;
shownPatienceMsg = true ;
2021-08-23 16:50:18 +02:00
await Task . Delay ( 500 ) ;
}
}
2024-08-11 20:47:36 +02:00
Config . Set ( "compressedPyVersion" , Updater . GetInstalledVer ( ) . ToString ( ) ) ;
Logger . Log ( "Done compressing python runtime." ) ;
Logger . WriteToFile ( compactOutput , true , "compact" ) ;
2021-08-23 16:50:18 +02:00
}
2024-08-11 20:47:36 +02:00
catch { }
Program . mainForm . SetWorking ( false ) ;
2021-08-23 16:50:18 +02:00
}
static void CompactOutputHandler ( object sendingProcess , DataReceivedEventArgs outLine )
{
if ( outLine = = null | | outLine . Data = = null )
return ;
2024-08-11 20:47:36 +02:00
compactOutput = $"{compactOutput}{outLine.Data}\n" ;
2021-08-23 16:50:18 +02:00
}
2022-07-22 09:31:58 +02:00
public static string GetPyCmd ( bool unbufferedStdOut = true , bool quiet = false )
2021-08-23 16:50:18 +02:00
{
if ( HasEmbeddedPyFolder ( ) )
{
Logger . Log ( "Using embedded Python runtime." ) ;
return Path . Combine ( GetPyFolder ( ) , "python.exe" ) . Wrap ( ) + ( unbufferedStdOut ? " -u " : "" ) ;
}
else
{
if ( IsSysPyInstalled ( ) )
{
return "python" + ( unbufferedStdOut ? " -u " : "" ) ;
}
else
{
2022-07-22 09:31:58 +02:00
if ( ! quiet )
{
2022-07-24 22:30:30 +02:00
UiUtils . ShowMessageBox ( "Neither the Flowframes Python Runtime nor System Python installation could be found!\nEither redownload Flowframes with the embedded Python runtime enabled or install Python/Pytorch yourself." ) ;
2022-07-22 09:31:58 +02:00
Interpolate . Cancel ( "Neither the Flowframes Python Runtime nor System Python installation could be found!" ) ;
}
2021-08-23 16:50:18 +02:00
}
}
return "" ;
}
public static bool HasEmbeddedPyFolder ( )
{
return ( Directory . Exists ( GetPyFolder ( ) ) & & IoUtils . GetDirSize ( GetPyFolder ( ) , false ) > 1024 * 1024 * 5 ) ;
}
public static string GetPyFolder ( )
{
if ( Directory . Exists ( Path . Combine ( Paths . GetPkgPath ( ) , "py-amp" ) ) )
return Path . Combine ( Paths . GetPkgPath ( ) , "py-amp" ) ;
if ( Directory . Exists ( Path . Combine ( Paths . GetPkgPath ( ) , "py-tu" ) ) )
return Path . Combine ( Paths . GetPkgPath ( ) , "py-tu" ) ;
return "" ;
}
2023-02-01 11:24:26 +01:00
private static bool? pytorchReadyCached = null ;
2021-08-23 16:50:18 +02:00
2023-02-01 11:24:26 +01:00
public static bool IsPytorchReady ( bool clearCachedValue = false )
2021-08-23 16:50:18 +02:00
{
2024-08-15 11:34:36 +02:00
if ( DisablePython )
return false ;
2023-02-01 11:24:26 +01:00
if ( clearCachedValue )
pytorchReadyCached = null ;
if ( pytorchReadyCached ! = null )
return ( bool ) pytorchReadyCached ;
2022-07-04 10:14:31 +02:00
2023-02-01 11:24:26 +01:00
bool pytorchReady = false ;
bool hasPyFolder = HasEmbeddedPyFolder ( ) ;
2021-08-23 16:50:18 +02:00
string torchVer = GetPytorchVer ( ) ;
2022-07-04 10:14:31 +02:00
2023-02-01 11:24:26 +01:00
pytorchReady = hasPyFolder | | ( ! string . IsNullOrWhiteSpace ( torchVer ) & & torchVer . Length < = 35 & & ! torchVer . Contains ( "ModuleNotFoundError" ) ) ;
pytorchReadyCached = pytorchReady ;
return pytorchReady ;
2021-08-23 16:50:18 +02:00
}
static string GetPytorchVer ( )
{
2024-08-15 11:34:36 +02:00
if ( DisablePython )
2024-08-11 20:32:36 +02:00
return "" ;
2021-08-23 16:50:18 +02:00
try
{
Process py = OsUtils . NewProcess ( true ) ;
2022-07-22 09:31:58 +02:00
py . StartInfo . Arguments = "\"/C\" " + GetPyCmd ( true , true ) + " -c \"import torch; print(torch.__version__)\"" ;
2022-07-04 10:14:31 +02:00
Logger . Log ( $"[DepCheck] CMD: {py.StartInfo.Arguments}" , true ) ;
2021-08-23 16:50:18 +02:00
py . Start ( ) ;
py . WaitForExit ( ) ;
string output = py . StandardOutput . ReadToEnd ( ) ;
2022-07-04 10:14:31 +02:00
Logger . Log ( "[DepCheck] Pytorch Check Output: " + output . Trim ( ) , true ) ;
2021-08-23 16:50:18 +02:00
return output ;
}
catch
{
return "" ;
}
}
public static bool IsSysPyInstalled ( )
{
if ( hasCheckedSysPy )
return sysPyInstalled ;
bool isInstalled = false ;
Logger . Log ( "Checking if system Python is available..." , true ) ;
string sysPyVer = GetSysPyVersion ( ) ;
2024-09-03 22:08:38 +02:00
if ( ! string . IsNullOrWhiteSpace ( sysPyVer ) & & ! sysPyVer . Lower ( ) . Contains ( "not found" ) & & sysPyVer . Length < = 35 )
2021-08-23 16:50:18 +02:00
{
isInstalled = true ;
Logger . Log ( "Using Python installation: " + sysPyVer , true ) ;
}
hasCheckedSysPy = true ;
sysPyInstalled = isInstalled ;
return sysPyInstalled ;
}
static string GetSysPyVersion ( )
{
string pythonOut = GetSysPythonOutput ( ) ;
Logger . Log ( "[DepCheck] System Python Check Output: " + pythonOut . Trim ( ) , true ) ;
try
{
string ver = pythonOut . Split ( '(' ) [ 0 ] . Trim ( ) ;
Logger . Log ( "[DepCheck] Sys Python Ver: " + ver , true ) ;
return ver ;
}
catch
{
return "" ;
}
}
static string GetSysPythonOutput ( )
{
Process py = OsUtils . NewProcess ( true ) ;
py . StartInfo . Arguments = "/C python -V" ;
Logger . Log ( "[DepCheck] CMD: " + py . StartInfo . Arguments , true ) ;
py . Start ( ) ;
py . WaitForExit ( ) ;
string output = py . StandardOutput . ReadToEnd ( ) ;
string err = py . StandardError . ReadToEnd ( ) ;
return output + "\n" + err ;
}
}
}