diff --git a/.github/workflows/windows-build.yaml b/.github/workflows/windows-build.yaml index 2449ce88..440b880c 100644 --- a/.github/workflows/windows-build.yaml +++ b/.github/workflows/windows-build.yaml @@ -73,11 +73,12 @@ jobs: # Step 9: Install vcpkg and ffmpeg - name: Install vcpkg and ffmpeg + shell: powershell run: | - git clone https://github.com/microsoft/vcpkg.git C:\vcpkg + if (!(Test-Path "C:\vcpkg")) { git clone https://github.com/microsoft/vcpkg.git C:\vcpkg } C:\vcpkg\bootstrap-vcpkg.bat - C:\vcpkg\vcpkg install ffmpeg - shell: cmd + cd openvino_bindings/third_party + C:\vcpkg\vcpkg install # Step 10: Download and Install OpenVINO Runtime - name: Download and Install OpenVINO Runtime 24.5.0 diff --git a/.gitignore b/.gitignore index 17b17888..1889f1c4 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,7 @@ migrate_working_dir/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. -#.vscode/ +.vscode/ # Flutter/Dart/Pub related **/doc/api/ diff --git a/assets/manifest.json b/assets/manifest.json index 5fac7d7f..50377b65 100644 --- a/assets/manifest.json +++ b/assets/manifest.json @@ -3,994 +3,1797 @@ { "name": "Mistral 7b Instruct V0.1", "id": "mistral-7b-instruct-v0.1-int8-ov", - "fileSize": 7824223166, + "fileSize": 7824223238, "optimizationPrecision": "int8", "contextWindow": 32768, - "description": "Chat with Mistral 7b Instruct V0.1 model", - "task": "text-generation" + "description": "Chat with Mistral 7b Instruct V0.1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Phi 3 Mini 4k Instruct", "id": "Phi-3-mini-4k-instruct-int4-ov", - "fileSize": 2637358233, + "fileSize": 2317366276, "optimizationPrecision": "int4", "contextWindow": 4096, - "description": "Chat with Phi 3 Mini 4k Instruct model", - "task": "text-generation" + "description": "Chat with Phi 3 Mini 4k Instruct", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Whisper Base", + "id": "whisper-base-fp16-ov", + "fileSize": 263786768, + "optimizationPrecision": "fp16", + "contextWindow": 0, + "description": "Transcribe video with Whisper Base", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" }, { "name": "Open_llama_3b_v2", "id": "open_llama_3b_v2-int8-ov", - "fileSize": 3689232132, + "fileSize": 3689232204, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with Open_llama_3b_v2 model", - "task": "text-generation" + "description": "Chat with Open_llama_3b_v2", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + } + ], + "all_models": [ + { + "name": "Distil Large V2", + "id": "distil-large-v2-fp16-ov", + "fileSize": 1623693910, + "optimizationPrecision": "fp16", + "contextWindow": 0, + "description": "Transcribe video with Distil Large V2", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" }, { - "name": "Open_llama_3b_v2", - "id": "open_llama_3b_v2-int8-ov", - "fileSize": 3689232132, + "name": "Distil Large V2", + "id": "distil-large-v2-int8-ov", + "fileSize": 811967934, "optimizationPrecision": "int8", - "contextWindow": 2048, - "description": "Chat with Open_llama_3b_v2 model", - "task": "text-generation" + "contextWindow": 0, + "description": "Transcribe video with Distil Large V2", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" }, { - "name": "Open_llama_3b_v2", - "id": "open_llama_3b_v2-int8-ov", - "fileSize": 3689232132, + "name": "Distil Large V3", + "id": "distil-large-v3-int4-ov", + "fileSize": 470886140, + "optimizationPrecision": "int4", + "contextWindow": 0, + "description": "Transcribe video with Distil Large V3", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Distil Large V3", + "id": "distil-large-v3-fp16-ov", + "fileSize": 1623692375, + "optimizationPrecision": "fp16", + "contextWindow": 0, + "description": "Transcribe video with Distil Large V3", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Distil Large V3", + "id": "distil-large-v3-int8-ov", + "fileSize": 811966358, "optimizationPrecision": "int8", - "contextWindow": 2048, - "description": "Chat with Open_llama_3b_v2 model", - "task": "text-generation" - } - ], - "all_models": [ + "contextWindow": 0, + "description": "Transcribe video with Distil Large V3", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Distil Large V2", + "id": "distil-large-v2-int4-ov", + "fileSize": 470887685, + "optimizationPrecision": "int4", + "contextWindow": 0, + "description": "Transcribe video with Distil Large V2", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Distil Whisper Base", + "id": "distil-whisper-base-fp16-ov", + "fileSize": 160942998, + "optimizationPrecision": "fp16", + "contextWindow": 0, + "description": "Transcribe video with Distil Whisper Base", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Distil Whisper Base", + "id": "distil-whisper-base-int4-ov", + "fileSize": 66325080, + "optimizationPrecision": "int4", + "contextWindow": 0, + "description": "Transcribe video with Distil Whisper Base", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Distil Whisper Base", + "id": "distil-whisper-base-int8-ov", + "fileSize": 88033050, + "optimizationPrecision": "int8", + "contextWindow": 0, + "description": "Transcribe video with Distil Whisper Base", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Distil Whisper Large V3", + "id": "distil-whisper-large-v3-int4-ov", + "fileSize": 905249204, + "optimizationPrecision": "int4", + "contextWindow": 0, + "description": "Transcribe video with Distil Whisper Large V3", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Distil Whisper Medium", + "id": "distil-whisper-medium-fp16-ov", + "fileSize": 1611734288, + "optimizationPrecision": "fp16", + "contextWindow": 0, + "description": "Transcribe video with Distil Whisper Medium", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Distil Whisper Large V3", + "id": "distil-whisper-large-v3-int8-ov", + "fileSize": 1642880457, + "optimizationPrecision": "int8", + "contextWindow": 0, + "description": "Transcribe video with Distil Whisper Large V3", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Distil Whisper Large V3", + "id": "distil-whisper-large-v3-fp16-ov", + "fileSize": 3318535654, + "optimizationPrecision": "fp16", + "contextWindow": 0, + "description": "Transcribe video with Distil Whisper Large V3", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Distil Whisper Medium", + "id": "distil-whisper-medium-int4-ov", + "fileSize": 467835674, + "optimizationPrecision": "int4", + "contextWindow": 0, + "description": "Transcribe video with Distil Whisper Medium", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Distil Whisper Medium", + "id": "distil-whisper-medium-int8-ov", + "fileSize": 820786325, + "optimizationPrecision": "int8", + "contextWindow": 0, + "description": "Transcribe video with Distil Whisper Medium", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Distil Whisper Tiny", + "id": "distil-whisper-tiny-int4-ov", + "fileSize": 42419245, + "optimizationPrecision": "int4", + "contextWindow": 0, + "description": "Transcribe video with Distil Whisper Tiny", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Distil Whisper Tiny", + "id": "distil-whisper-tiny-int8-ov", + "fileSize": 50341791, + "optimizationPrecision": "int8", + "contextWindow": 0, + "description": "Transcribe video with Distil Whisper Tiny", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Distil Whisper Tiny", + "id": "distil-whisper-tiny-fp16-ov", + "fileSize": 87657508, + "optimizationPrecision": "fp16", + "contextWindow": 0, + "description": "Transcribe video with Distil Whisper Tiny", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Whisper Tiny", + "id": "whisper-tiny-int4-ov", + "fileSize": 68582454, + "optimizationPrecision": "int4", + "contextWindow": 0, + "description": "Transcribe video with Whisper Tiny", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Whisper Base", + "id": "whisper-base-int8-ov", + "fileSize": 140207692, + "optimizationPrecision": "int8", + "contextWindow": 0, + "description": "Transcribe video with Whisper Base", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Whisper Medium", + "id": "whisper-medium-int8-ov", + "fileSize": 1250473365, + "optimizationPrecision": "int8", + "contextWindow": 0, + "description": "Transcribe video with Whisper Medium", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Whisper Medium", + "id": "whisper-medium-int4-ov", + "fileSize": 719474580, + "optimizationPrecision": "int4", + "contextWindow": 0, + "description": "Transcribe video with Whisper Medium", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Whisper Tiny", + "id": "whisper-tiny-int8-ov", + "fileSize": 80769346, + "optimizationPrecision": "int8", + "contextWindow": 0, + "description": "Transcribe video with Whisper Tiny", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Whisper Base", + "id": "whisper-base-int4-ov", + "fileSize": 107331169, + "optimizationPrecision": "int4", + "contextWindow": 0, + "description": "Transcribe video with Whisper Base", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Whisper Large V3", + "id": "whisper-large-v3-fp16-ov", + "fileSize": 5038558437, + "optimizationPrecision": "fp16", + "contextWindow": 0, + "description": "Transcribe video with Whisper Large V3", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Whisper Medium", + "id": "whisper-medium-fp16-ov", + "fileSize": 2465759114, + "optimizationPrecision": "fp16", + "contextWindow": 0, + "description": "Transcribe video with Whisper Medium", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Whisper Tiny", + "id": "whisper-tiny-fp16-ov", + "fileSize": 147388830, + "optimizationPrecision": "fp16", + "contextWindow": 0, + "description": "Transcribe video with Whisper Tiny", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, + { + "name": "Whisper Base", + "id": "whisper-base-fp16-ov", + "fileSize": 263786768, + "optimizationPrecision": "fp16", + "contextWindow": 0, + "description": "Transcribe video with Whisper Base", + "task": "speech", + "author": "OpenVINO", + "collection": "speech-to-text-672321d5c070537a178a8aeb" + }, { "name": "Phi 2", "id": "phi-2-fp16-ov", - "fileSize": 5978786593, + "fileSize": 5978786613, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with Phi 2 model", - "task": "text-generation" + "description": "Chat with Phi 2", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Phi 2", "id": "phi-2-int8-ov", - "fileSize": 3004595529, + "fileSize": 3004595590, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with Phi 2 model", - "task": "text-generation" + "description": "Chat with Phi 2", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Mistral 7b Instruct V0.1", "id": "mistral-7b-instruct-v0.1-int8-ov", - "fileSize": 7824223166, + "fileSize": 7824223238, "optimizationPrecision": "int8", "contextWindow": 32768, - "description": "Chat with Mistral 7b Instruct V0.1 model", - "task": "text-generation" + "description": "Chat with Mistral 7b Instruct V0.1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Mistral 7b Instruct V0.1", "id": "mistral-7b-instruct-v0.1-fp16-ov", - "fileSize": 15576387089, + "fileSize": 15576387130, "optimizationPrecision": "fp16", "contextWindow": 32768, - "description": "Chat with Mistral 7b Instruct V0.1 model", - "task": "text-generation" + "description": "Chat with Mistral 7b Instruct V0.1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Mistral 7b Instruct V0.1", "id": "mistral-7b-instruct-v0.1-int4-ov", - "fileSize": 4967917794, + "fileSize": 4967917876, "optimizationPrecision": "int4", "contextWindow": 32768, - "description": "Chat with Mistral 7b Instruct V0.1 model", - "task": "text-generation" + "description": "Chat with Mistral 7b Instruct V0.1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Codegen25 7b Multi", "id": "codegen25-7b-multi-fp16-ov", - "fileSize": 14822539137, + "fileSize": 14822064608, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with Codegen25 7b Multi model", - "task": "text-generation" + "description": "Chat with Codegen25 7b Multi", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Codegen25 7b Multi", "id": "codegen25-7b-multi-int8-ov", - "fileSize": 7414035410, + "fileSize": 7413624227, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with Codegen25 7b Multi model", - "task": "text-generation" + "description": "Chat with Codegen25 7b Multi", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Mixtral 8x7b Instruct V0.1", "id": "mixtral-8x7b-instruct-v0.1-int4-ov", - "fileSize": 30833964831, + "fileSize": 30833964913, "optimizationPrecision": "int4", "contextWindow": 32768, - "description": "Chat with Mixtral 8x7b Instruct V0.1 model", - "task": "text-generation" + "description": "Chat with Mixtral 8x7b Instruct V0.1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Mixtral 8x7B Instruct V0.1", "id": "Mixtral-8x7B-Instruct-v0.1-int8-ov", - "fileSize": 50160688476, + "fileSize": 50160688558, "optimizationPrecision": "int8", "contextWindow": 32768, - "description": "Chat with Mixtral 8x7B Instruct V0.1 model", - "task": "text-generation" + "description": "Chat with Mixtral 8x7B Instruct V0.1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Notus 7b V1", "id": "notus-7b-v1-fp16-ov", - "fileSize": 15576386988, + "fileSize": 15576387018, "optimizationPrecision": "fp16", "contextWindow": 32768, - "description": "Chat with Notus 7b V1 model", - "task": "text-generation" + "description": "Chat with Notus 7b V1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Notus 7b V1", "id": "notus-7b-v1-int8-ov", - "fileSize": 7803125798, + "fileSize": 7803125869, "optimizationPrecision": "int8", "contextWindow": 32768, - "description": "Chat with Notus 7b V1 model", - "task": "text-generation" + "description": "Chat with Notus 7b V1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Neural Chat 7b V3 3", "id": "neural-chat-7b-v3-3-fp16-ov", - "fileSize": 15576386599, + "fileSize": 15576386640, "optimizationPrecision": "fp16", "contextWindow": 32768, - "description": "Chat with Neural Chat 7b V3 3 model", - "task": "text-generation" + "description": "Chat with Neural Chat 7b V3 3", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Neural Chat 7b V3 3", "id": "neural-chat-7b-v3-3-int8-ov", - "fileSize": 7803125410, + "fileSize": 7803125481, "optimizationPrecision": "int8", "contextWindow": 32768, - "description": "Chat with Neural Chat 7b V3 3 model", - "task": "text-generation" + "description": "Chat with Neural Chat 7b V3 3", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Zephyr 7b Beta", "id": "zephyr-7b-beta-int8-ov", - "fileSize": 7803126061, + "fileSize": 7803126133, "optimizationPrecision": "int8", "contextWindow": 32768, - "description": "Chat with Zephyr 7b Beta model", - "task": "text-generation" + "description": "Chat with Zephyr 7b Beta", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Zephyr 7b Beta", "id": "zephyr-7b-beta-int4-ov", - "fileSize": 4904138531, + "fileSize": 4904138613, "optimizationPrecision": "int4", "contextWindow": 32768, - "description": "Chat with Zephyr 7b Beta model", - "task": "text-generation" + "description": "Chat with Zephyr 7b Beta", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Dolly V2 3b", "id": "dolly-v2-3b-int4-ov", - "fileSize": 2434908470, + "fileSize": 1694037426, "optimizationPrecision": "int4", "contextWindow": 2048, - "description": "Chat with Dolly V2 3b model", - "task": "text-generation" + "description": "Chat with Dolly V2 3b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Dolly V2 3b", "id": "dolly-v2-3b-int8-ov", - "fileSize": 2993180745, + "fileSize": 2993264386, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with Dolly V2 3b model", - "task": "text-generation" + "description": "Chat with Dolly V2 3b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Dolly V2 3b", "id": "dolly-v2-3b-fp16-ov", - "fileSize": 5967078157, + "fileSize": 5967350336, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with Dolly V2 3b model", - "task": "text-generation" + "description": "Chat with Dolly V2 3b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Codegen2 3_7B_P", "id": "codegen2-3_7B_P-int4-ov", - "fileSize": 2252764320, + "fileSize": 2252764402, "optimizationPrecision": "int4", "contextWindow": 2048, - "description": "Chat with Codegen2 3_7B_P model", - "task": "text-generation" + "description": "Chat with Codegen2 3_7B_P", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Codegen2 3_7B_P", "id": "codegen2-3_7B_P-fp16-ov", - "fileSize": 7835969716, + "fileSize": 7835969757, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with Codegen2 3_7B_P model", - "task": "text-generation" + "description": "Chat with Codegen2 3_7B_P", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Zephyr 7b Beta", "id": "zephyr-7b-beta-fp16-ov", - "fileSize": 15576387241, + "fileSize": 15576387282, "optimizationPrecision": "fp16", "contextWindow": 32768, - "description": "Chat with Zephyr 7b Beta model", - "task": "text-generation" + "description": "Chat with Zephyr 7b Beta", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Codegen2 3_7B_P", "id": "codegen2-3_7B_P-int8-ov", - "fileSize": 3927738589, + "fileSize": 3927738671, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with Codegen2 3_7B_P model", - "task": "text-generation" + "description": "Chat with Codegen2 3_7B_P", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "TinyLlama 1.1B Chat V1.0", "id": "TinyLlama-1.1B-Chat-v1.0-fp16-ov", - "fileSize": 2368272475, + "fileSize": 2368272527, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with TinyLlama 1.1B Chat V1.0 model", - "task": "text-generation" + "description": "Chat with TinyLlama 1.1B Chat V1.0", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "TinyLlama 1.1B Chat V1.0", "id": "TinyLlama-1.1B-Chat-v1.0-int4-ov", - "fileSize": 668269097, + "fileSize": 668269179, "optimizationPrecision": "int4", "contextWindow": 2048, - "description": "Chat with TinyLlama 1.1B Chat V1.0 model", - "task": "text-generation" + "description": "Chat with TinyLlama 1.1B Chat V1.0", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "TinyLlama 1.1B Chat V1.0", "id": "TinyLlama-1.1B-Chat-v1.0-int8-ov", - "fileSize": 1187586826, + "fileSize": 1187586908, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with TinyLlama 1.1B Chat V1.0 model", - "task": "text-generation" + "description": "Chat with TinyLlama 1.1B Chat V1.0", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Gpt Neox 20b", "id": "gpt-neox-20b-int8-ov", - "fileSize": 22128276574, + "fileSize": 22128276646, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with Gpt Neox 20b model", - "task": "text-generation" + "description": "Chat with Gpt Neox 20b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Gpt Neox 20b", "id": "gpt-neox-20b-fp16-ov", - "fileSize": 44140098869, + "fileSize": 44140098910, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with Gpt Neox 20b model", - "task": "text-generation" - }, - { - "name": "Gpt Neox 20b", - "id": "gpt-neox-20b-int4-ov", - "fileSize": 13968006447, - "optimizationPrecision": "int4", - "contextWindow": 2048, - "description": "Chat with Gpt Neox 20b model", - "task": "text-generation" + "description": "Chat with Gpt Neox 20b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Gpt J 6b", "id": "gpt-j-6b-int4-ov", - "fileSize": 4196810211, + "fileSize": 4196810272, "optimizationPrecision": "int4", "contextWindow": 2048, - "description": "Chat with Gpt J 6b model", - "task": "text-generation" + "description": "Chat with Gpt J 6b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Gpt J 6b", "id": "gpt-j-6b-int8-ov", - "fileSize": 6515945720, + "fileSize": 6515945792, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with Gpt J 6b model", - "task": "text-generation" + "description": "Chat with Gpt J 6b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Gpt J 6b", "id": "gpt-j-6b-fp16-ov", - "fileSize": 13001251300, + "fileSize": 13001251330, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with Gpt J 6b model", - "task": "text-generation" + "description": "Chat with Gpt J 6b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Falcon 7b Instruct", "id": "falcon-7b-instruct-int4-ov", - "fileSize": 3959308647, + "fileSize": 3959308719, "optimizationPrecision": "int4", "contextWindow": 2048, - "description": "Chat with Falcon 7b Instruct model", - "task": "text-generation" + "description": "Chat with Falcon 7b Instruct", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Falcon 7b Instruct", "id": "falcon-7b-instruct-fp16-ov", - "fileSize": 14825512501, + "fileSize": 14825512542, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with Falcon 7b Instruct model", - "task": "text-generation" + "description": "Chat with Falcon 7b Instruct", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Falcon 7b Instruct", "id": "falcon-7b-instruct-int8-ov", - "fileSize": 7449021953, + "fileSize": 7449022025, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with Falcon 7b Instruct model", - "task": "text-generation" + "description": "Chat with Falcon 7b Instruct", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Open_llama_7b_v2", "id": "open_llama_7b_v2-int8-ov", - "fileSize": 7243946706, + "fileSize": 7243946788, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with Open_llama_7b_v2 model", - "task": "text-generation" + "description": "Chat with Open_llama_7b_v2", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Open_llama_7b_v2", "id": "open_llama_7b_v2-int4-ov", - "fileSize": 4581255942, + "fileSize": 4581256014, "optimizationPrecision": "int4", "contextWindow": 2048, - "description": "Chat with Open_llama_7b_v2 model", - "task": "text-generation" + "description": "Chat with Open_llama_7b_v2", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Open_llama_7b_v2", "id": "open_llama_7b_v2-fp16-ov", - "fileSize": 14502136910, + "fileSize": 14502136961, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with Open_llama_7b_v2 model", - "task": "text-generation" + "description": "Chat with Open_llama_7b_v2", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Open_llama_3b_v2", "id": "open_llama_3b_v2-int8-ov", - "fileSize": 3689232132, + "fileSize": 3689232204, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with Open_llama_3b_v2 model", - "task": "text-generation" + "description": "Chat with Open_llama_3b_v2", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Open_llama_3b_v2", "id": "open_llama_3b_v2-fp16-ov", - "fileSize": 7361187312, + "fileSize": 7361187363, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with Open_llama_3b_v2 model", - "task": "text-generation" + "description": "Chat with Open_llama_3b_v2", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Phi 2", "id": "phi-2-int4-ov", - "fileSize": 1963097577, + "fileSize": 1963097638, "optimizationPrecision": "int4", "contextWindow": 2048, - "description": "Chat with Phi 2 model", - "task": "text-generation" + "description": "Chat with Phi 2", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Neural Chat 7b V3 3", "id": "neural-chat-7b-v3-3-int4-ov", - "fileSize": 4957174834, + "fileSize": 4957174906, "optimizationPrecision": "int4", "contextWindow": 32768, - "description": "Chat with Neural Chat 7b V3 3 model", - "task": "text-generation" + "description": "Chat with Neural Chat 7b V3 3", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Notus 7b V1", "id": "notus-7b-v1-int4-ov", - "fileSize": 4957175373, + "fileSize": 4957175444, "optimizationPrecision": "int4", "contextWindow": 32768, - "description": "Chat with Notus 7b V1 model", - "task": "text-generation" + "description": "Chat with Notus 7b V1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "RedPajama INCITE Chat 3B V1", "id": "RedPajama-INCITE-Chat-3B-v1-int8-ov", - "fileSize": 3003403190, + "fileSize": 2993181070, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with RedPajama INCITE Chat 3B V1 model", - "task": "text-generation" + "description": "Chat with RedPajama INCITE Chat 3B V1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "RedPajama INCITE 7B Instruct", "id": "RedPajama-INCITE-7B-Instruct-fp16-ov", - "fileSize": 14717999973, + "fileSize": 14718000035, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with RedPajama INCITE 7B Instruct model", - "task": "text-generation" + "description": "Chat with RedPajama INCITE 7B Instruct", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "RedPajama INCITE 7B Instruct", "id": "RedPajama-INCITE-7B-Instruct-int4-ov", - "fileSize": 7384270376, + "fileSize": 7384270468, "optimizationPrecision": "int4", "contextWindow": 2048, - "description": "Chat with RedPajama INCITE 7B Instruct model", - "task": "text-generation" + "description": "Chat with RedPajama INCITE 7B Instruct", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "RedPajama INCITE 7B Chat", "id": "RedPajama-INCITE-7B-Chat-int4-ov", - "fileSize": 4753728620, + "fileSize": 4753728702, "optimizationPrecision": "int4", "contextWindow": 2048, - "description": "Chat with RedPajama INCITE 7B Chat model", - "task": "text-generation" + "description": "Chat with RedPajama INCITE 7B Chat", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "RedPajama INCITE 7B Instruct", "id": "RedPajama-INCITE-7B-Instruct-int8-ov", - "fileSize": 7384270355, + "fileSize": 7384270448, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with RedPajama INCITE 7B Instruct model", - "task": "text-generation" + "description": "Chat with RedPajama INCITE 7B Instruct", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "RedPajama INCITE 7B Chat", "id": "RedPajama-INCITE-7B-Chat-fp16-ov", - "fileSize": 14717999600, + "fileSize": 14717999652, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with RedPajama INCITE 7B Chat model", - "task": "text-generation" + "description": "Chat with RedPajama INCITE 7B Chat", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "RedPajama INCITE Chat 3B V1", "id": "RedPajama-INCITE-Chat-3B-v1-int4-ov", - "fileSize": 1972726843, + "fileSize": 1693954060, "optimizationPrecision": "int4", "contextWindow": 2048, - "description": "Chat with RedPajama INCITE Chat 3B V1 model", - "task": "text-generation" + "description": "Chat with RedPajama INCITE Chat 3B V1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "RedPajama INCITE 7B Chat", "id": "RedPajama-INCITE-7B-Chat-int8-ov", - "fileSize": 7384270239, + "fileSize": 7384270331, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with RedPajama INCITE 7B Chat model", - "task": "text-generation" + "description": "Chat with RedPajama INCITE 7B Chat", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "RedPajama INCITE Chat 3B V1", "id": "RedPajama-INCITE-Chat-3B-v1-fp16-ov", - "fileSize": 5977741177, + "fileSize": 5967266928, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with RedPajama INCITE Chat 3B V1 model", - "task": "text-generation" - }, - { - "name": "Dolly V2 12b", - "id": "dolly-v2-12b-int4-ov", - "fileSize": 8093674841, - "optimizationPrecision": "int4", - "contextWindow": 2048, - "description": "Chat with Dolly V2 12b model", - "task": "text-generation" + "description": "Chat with RedPajama INCITE Chat 3B V1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Dolly V2 7b", "id": "dolly-v2-7b-int4-ov", - "fileSize": 4753855475, + "fileSize": 4753855546, "optimizationPrecision": "int4", "contextWindow": 2048, - "description": "Chat with Dolly V2 7b model", - "task": "text-generation" + "description": "Chat with Dolly V2 7b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Dolly V2 7b", "id": "dolly-v2-7b-int8-ov", - "fileSize": 7384407579, + "fileSize": 7384407651, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with Dolly V2 7b model", - "task": "text-generation" + "description": "Chat with Dolly V2 7b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Dolly V2 7b", "id": "dolly-v2-7b-fp16-ov", - "fileSize": 14718147683, + "fileSize": 14718147724, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with Dolly V2 7b model", - "task": "text-generation" + "description": "Chat with Dolly V2 7b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Mistral 7B Instruct V0.2", "id": "Mistral-7B-Instruct-v0.2-int8-ov", - "fileSize": 7823897819, + "fileSize": 7823897901, "optimizationPrecision": "int8", "contextWindow": 32768, - "description": "Chat with Mistral 7B Instruct V0.2 model", - "task": "text-generation" + "description": "Chat with Mistral 7B Instruct V0.2", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Dolly V2 12b", "id": "dolly-v2-12b-int8-ov", - "fileSize": 12785790267, + "fileSize": 12785790338, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with Dolly V2 12b model", - "task": "text-generation" + "description": "Chat with Dolly V2 12b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Mistral 7B Instruct V0.2", "id": "Mistral-7B-Instruct-v0.2-int4-ov", - "fileSize": 4957164416, + "fileSize": 4957164498, "optimizationPrecision": "int4", "contextWindow": 32768, - "description": "Chat with Mistral 7B Instruct V0.2 model", - "task": "text-generation" + "description": "Chat with Mistral 7B Instruct V0.2", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Mistral 7B Instruct V0.2", "id": "Mistral-7B-Instruct-v0.2-fp16-ov", - "fileSize": 15576062131, + "fileSize": 15576062183, "optimizationPrecision": "fp16", "contextWindow": 32768, - "description": "Chat with Mistral 7B Instruct V0.2 model", - "task": "text-generation" + "description": "Chat with Mistral 7B Instruct V0.2", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Codegen25 7b Multi", "id": "codegen25-7b-multi-int4-ov", - "fileSize": 4760257312, + "fileSize": 4074538822, "optimizationPrecision": "int4", "contextWindow": 2048, - "description": "Chat with Codegen25 7b Multi model", - "task": "text-generation" + "description": "Chat with Codegen25 7b Multi", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Persimmon 8b Chat", "id": "persimmon-8b-chat-int4-ov", - "fileSize": 6896839595, + "fileSize": 6896839666, "optimizationPrecision": "int4", "contextWindow": 2048, - "description": "Chat with Persimmon 8b Chat model", - "task": "text-generation" + "description": "Chat with Persimmon 8b Chat", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Persimmon 8b Chat", "id": "persimmon-8b-chat-int8-ov", - "fileSize": 12791514405, + "fileSize": 12791514477, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with Persimmon 8b Chat model", - "task": "text-generation" + "description": "Chat with Persimmon 8b Chat", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Pythia 1.4b", "id": "pythia-1.4b-int4-ov", - "fileSize": 6890411793, + "fileSize": 6890411865, "optimizationPrecision": "int4", "contextWindow": 2048, - "description": "Chat with Pythia 1.4b model", - "task": "text-generation" + "description": "Chat with Pythia 1.4b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Pythia 1.4b", "id": "pythia-1.4b-int8-ov", - "fileSize": 12785086603, + "fileSize": 12785086675, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with Pythia 1.4b model", - "task": "text-generation" + "description": "Chat with Pythia 1.4b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Persimmon 8b Chat", "id": "persimmon-8b-chat-fp16-ov", - "fileSize": 25461688234, + "fileSize": 25461688275, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with Persimmon 8b Chat model", - "task": "text-generation" + "description": "Chat with Persimmon 8b Chat", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Pythia 1.4b", "id": "pythia-1.4b-fp16-ov", - "fileSize": 25455260443, + "fileSize": 25455260474, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with Pythia 1.4b model", - "task": "text-generation" - }, - { - "name": "Pythia 12b", - "id": "pythia-12b-int4-ov", - "fileSize": 3824586206, - "optimizationPrecision": "int4", - "contextWindow": 2048, - "description": "Chat with Pythia 12b model", - "task": "text-generation" + "description": "Chat with Pythia 1.4b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Pythia 12b", "id": "pythia-12b-int8-ov", - "fileSize": 7153039029, + "fileSize": 7153039101, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with Pythia 12b model", - "task": "text-generation" + "description": "Chat with Pythia 12b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Pythia 2.8b", "id": "pythia-2.8b-int8-ov", - "fileSize": 7153039039, + "fileSize": 7153039111, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with Pythia 2.8b model", - "task": "text-generation" + "description": "Chat with Pythia 2.8b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Pythia 2.8b", "id": "pythia-2.8b-int4-ov", - "fileSize": 3824586216, + "fileSize": 3824586288, "optimizationPrecision": "int4", "contextWindow": 2048, - "description": "Chat with Pythia 2.8b model", - "task": "text-generation" + "description": "Chat with Pythia 2.8b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Pythia 12b", "id": "pythia-12b-fp16-ov", - "fileSize": 14293243461, + "fileSize": 14293243502, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with Pythia 12b model", - "task": "text-generation" + "description": "Chat with Pythia 12b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Pythia 6.9b", "id": "pythia-6.9b-int4-ov", - "fileSize": 3824586216, + "fileSize": 3824586288, "optimizationPrecision": "int4", "contextWindow": 2048, - "description": "Chat with Pythia 6.9b model", - "task": "text-generation" + "description": "Chat with Pythia 6.9b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Pythia 6.9b", "id": "pythia-6.9b-int8-ov", - "fileSize": 7153039039, + "fileSize": 7153039111, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with Pythia 6.9b model", - "task": "text-generation" + "description": "Chat with Pythia 6.9b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Pythia 2.8b", "id": "pythia-2.8b-fp16-ov", - "fileSize": 14293243256, + "fileSize": 14293243287, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with Pythia 2.8b model", - "task": "text-generation" + "description": "Chat with Pythia 2.8b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Pythia 6.9b", "id": "pythia-6.9b-fp16-ov", - "fileSize": 14293243256, + "fileSize": 14293243287, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with Pythia 6.9b model", - "task": "text-generation" + "description": "Chat with Pythia 6.9b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Pythia 1b", "id": "pythia-1b-int4-ov", - "fileSize": 669587847, + "fileSize": 669587919, "optimizationPrecision": "int4", "contextWindow": 2048, - "description": "Chat with Pythia 1b model", - "task": "text-generation" + "description": "Chat with Pythia 1b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Pythia 1b", "id": "pythia-1b-int8-ov", - "fileSize": 1107284420, + "fileSize": 1107284481, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with Pythia 1b model", - "task": "text-generation" + "description": "Chat with Pythia 1b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Pythia 1b", "id": "pythia-1b-fp16-ov", - "fileSize": 2181025578, + "fileSize": 2181025619, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with Pythia 1b model", - "task": "text-generation" + "description": "Chat with Pythia 1b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Neural Chat 7b V1 1", "id": "neural-chat-7b-v1-1-int4-ov", - "fileSize": 3824586268, + "fileSize": 3824586350, "optimizationPrecision": "int4", "contextWindow": 2048, - "description": "Chat with Neural Chat 7b V1 1 model", - "task": "text-generation" + "description": "Chat with Neural Chat 7b V1 1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Neural Chat 7b V1 1", "id": "neural-chat-7b-v1-1-int8-ov", - "fileSize": 7153039101, + "fileSize": 7153039173, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with Neural Chat 7b V1 1 model", - "task": "text-generation" + "description": "Chat with Neural Chat 7b V1 1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Neural Chat 7b V1 1", "id": "neural-chat-7b-v1-1-fp16-ov", - "fileSize": 14293243287, + "fileSize": 14293243328, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with Neural Chat 7b V1 1 model", - "task": "text-generation" + "description": "Chat with Neural Chat 7b V1 1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Phi 3 Medium 4k Instruct", "id": "Phi-3-medium-4k-instruct-fp16-ov", - "fileSize": 29965606794, + "fileSize": 29965606845, "optimizationPrecision": "fp16", "contextWindow": 4096, - "description": "Chat with Phi 3 Medium 4k Instruct model", - "task": "text-generation" + "description": "Chat with Phi 3 Medium 4k Instruct", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Phi 3 Medium 4k Instruct", "id": "Phi-3-medium-4k-instruct-int4-ov", - "fileSize": 7964805299, + "fileSize": 7964805381, "optimizationPrecision": "int4", "contextWindow": 4096, - "description": "Chat with Phi 3 Medium 4k Instruct model", - "task": "text-generation" + "description": "Chat with Phi 3 Medium 4k Instruct", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Phi 3 Medium 4k Instruct", "id": "Phi-3-medium-4k-instruct-int8-ov", - "fileSize": 15040585641, + "fileSize": 15040585723, "optimizationPrecision": "int8", "contextWindow": 4096, - "description": "Chat with Phi 3 Medium 4k Instruct model", - "task": "text-generation" + "description": "Chat with Phi 3 Medium 4k Instruct", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Mpt 7b", "id": "mpt-7b-int8-ov", - "fileSize": 7146788625, + "fileSize": 7146788697, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with Mpt 7b model", - "task": "text-generation" + "description": "Chat with Mpt 7b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Mpt 7b", "id": "mpt-7b-fp16-ov", - "fileSize": 14286814799, + "fileSize": 14286814840, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with Mpt 7b model", - "task": "text-generation" + "description": "Chat with Mpt 7b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Starcoder2 15b", "id": "starcoder2-15b-int8-ov", - "fileSize": 17190289720, + "fileSize": 17190289792, "optimizationPrecision": "int8", "contextWindow": 16384, - "description": "Chat with Starcoder2 15b model", - "task": "text-generation" + "description": "Chat with Starcoder2 15b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Starcoder2 15b", "id": "starcoder2-15b-int4-ov", - "fileSize": 9169658515, + "fileSize": 9169658587, "optimizationPrecision": "int4", "contextWindow": 16384, - "description": "Chat with Starcoder2 15b model", - "task": "text-generation" + "description": "Chat with Starcoder2 15b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Starcoder2 15b", "id": "starcoder2-15b-fp16-ov", - "fileSize": 34262102706, + "fileSize": 34262102747, "optimizationPrecision": "fp16", "contextWindow": 16384, - "description": "Chat with Starcoder2 15b model", - "task": "text-generation" + "description": "Chat with Starcoder2 15b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Starcoder2 7b", "id": "starcoder2-7b-fp16-ov", - "fileSize": 15470719144, + "fileSize": 15470719185, "optimizationPrecision": "fp16", "contextWindow": 16384, - "description": "Chat with Starcoder2 7b model", - "task": "text-generation" + "description": "Chat with Starcoder2 7b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Starcoder2 7b", "id": "starcoder2-7b-int4-ov", - "fileSize": 4111254624, + "fileSize": 4111254696, "optimizationPrecision": "int4", "contextWindow": 16384, - "description": "Chat with Starcoder2 7b model", - "task": "text-generation" + "description": "Chat with Starcoder2 7b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Starcoder2 7b", "id": "starcoder2-7b-int8-ov", - "fileSize": 7729586294, + "fileSize": 7729586365, "optimizationPrecision": "int8", "contextWindow": 16384, - "description": "Chat with Starcoder2 7b model", - "task": "text-generation" + "description": "Chat with Starcoder2 7b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Starcoder2 3b", "id": "starcoder2-3b-int4-ov", - "fileSize": 1780962229, + "fileSize": 1780962300, "optimizationPrecision": "int4", "contextWindow": 16384, - "description": "Chat with Starcoder2 3b model", - "task": "text-generation" + "description": "Chat with Starcoder2 3b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Starcoder2 3b", "id": "starcoder2-3b-fp16-ov", - "fileSize": 6526229346, + "fileSize": 6526229387, "optimizationPrecision": "fp16", "contextWindow": 16384, - "description": "Chat with Starcoder2 3b model", - "task": "text-generation" + "description": "Chat with Starcoder2 3b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Starcoder2 3b", "id": "starcoder2-3b-int8-ov", - "fileSize": 3273295377, + "fileSize": 3273295448, "optimizationPrecision": "int8", "contextWindow": 16384, - "description": "Chat with Starcoder2 3b model", - "task": "text-generation" + "description": "Chat with Starcoder2 3b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Phi 3 Mini 4k Instruct", "id": "Phi-3-mini-4k-instruct-fp16-ov", - "fileSize": 8209920736, + "fileSize": 8212081759, "optimizationPrecision": "fp16", "contextWindow": 4096, - "description": "Chat with Phi 3 Mini 4k Instruct model", - "task": "text-generation" + "description": "Chat with Phi 3 Mini 4k Instruct", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Phi 3 Mini 128k Instruct", "id": "Phi-3-mini-128k-instruct-fp16-ov", - "fileSize": 8210027955, + "fileSize": 8210027996, "optimizationPrecision": "fp16", "contextWindow": 131072, - "description": "Chat with Phi 3 Mini 128k Instruct model", - "task": "text-generation" + "description": "Chat with Phi 3 Mini 128k Instruct", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Phi 3 Mini 128k Instruct", "id": "Phi-3-mini-128k-instruct-int4-ov", - "fileSize": 2637434178, + "fileSize": 2637434260, "optimizationPrecision": "int4", "contextWindow": 131072, - "description": "Chat with Phi 3 Mini 128k Instruct model", - "task": "text-generation" + "description": "Chat with Phi 3 Mini 128k Instruct", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Phi 3 Mini 4k Instruct", "id": "Phi-3-mini-4k-instruct-int4-ov", - "fileSize": 2637358233, + "fileSize": 2317366276, "optimizationPrecision": "int4", "contextWindow": 4096, - "description": "Chat with Phi 3 Mini 4k Instruct model", - "task": "text-generation" + "description": "Chat with Phi 3 Mini 4k Instruct", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Phi 3 Mini 4k Instruct", "id": "Phi-3-mini-4k-instruct-int8-ov", - "fileSize": 4108269167, + "fileSize": 4110513544, "optimizationPrecision": "int8", "contextWindow": 4096, - "description": "Chat with Phi 3 Mini 4k Instruct model", - "task": "text-generation" + "description": "Chat with Phi 3 Mini 4k Instruct", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Phi 3 Mini 128k Instruct", "id": "Phi-3-mini-128k-instruct-int8-ov", - "fileSize": 4108345114, + "fileSize": 4108345195, "optimizationPrecision": "int8", "contextWindow": 131072, - "description": "Chat with Phi 3 Mini 128k Instruct model", - "task": "text-generation" + "description": "Chat with Phi 3 Mini 128k Instruct", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "Open_llama_3b_v2", "id": "open_llama_3b_v2-int4-ov", - "fileSize": 1960434251, + "fileSize": 1960434322, "optimizationPrecision": "int4", "contextWindow": 2048, - "description": "Chat with Open_llama_3b_v2 model", - "task": "text-generation" + "description": "Chat with Open_llama_3b_v2", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "RedPajama INCITE Instruct 3B V1", "id": "RedPajama-INCITE-Instruct-3B-v1-fp16-ov", - "fileSize": 5975908581, + "fileSize": 5975908643, "optimizationPrecision": "fp16", "contextWindow": 2048, - "description": "Chat with RedPajama INCITE Instruct 3B V1 model", - "task": "text-generation" + "description": "Chat with RedPajama INCITE Instruct 3B V1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "RedPajama INCITE Instruct 3B V1", "id": "RedPajama-INCITE-Instruct-3B-v1-int4-ov", - "fileSize": 1970894247, + "fileSize": 1970894350, "optimizationPrecision": "int4", "contextWindow": 2048, - "description": "Chat with RedPajama INCITE Instruct 3B V1 model", - "task": "text-generation" + "description": "Chat with RedPajama INCITE Instruct 3B V1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" }, { "name": "RedPajama INCITE Instruct 3B V1", "id": "RedPajama-INCITE-Instruct-3B-v1-int8-ov", - "fileSize": 3001571035, + "fileSize": 3001571127, + "optimizationPrecision": "int8", + "contextWindow": 2048, + "description": "Chat with RedPajama INCITE Instruct 3B V1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Gemma 2b It", + "id": "gemma-2b-it-fp16-ov", + "fileSize": 5437344390, + "optimizationPrecision": "fp16", + "contextWindow": 8192, + "description": "Chat with Gemma 2b It", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Gemma 2b It", + "id": "gemma-2b-it-int8-ov", + "fileSize": 2753201206, + "optimizationPrecision": "int8", + "contextWindow": 8192, + "description": "Chat with Gemma 2b It", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Gemma 2b", + "id": "gemma-2b-fp16-ov", + "fileSize": 5437342382, + "optimizationPrecision": "fp16", + "contextWindow": 8192, + "description": "Chat with Gemma 2b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Gemma 2b", + "id": "gemma-2b-int4-ov", + "fileSize": 1722552895, + "optimizationPrecision": "int4", + "contextWindow": 8192, + "description": "Chat with Gemma 2b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Gemma 2b It", + "id": "gemma-2b-it-int4-ov", + "fileSize": 1722555876, + "optimizationPrecision": "int4", + "contextWindow": 8192, + "description": "Chat with Gemma 2b It", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Gemma 7b", + "id": "gemma-7b-fp16-ov", + "fileSize": 18419687858, + "optimizationPrecision": "fp16", + "contextWindow": 8192, + "description": "Chat with Gemma 7b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Gemma 7b", + "id": "gemma-7b-int4-ov", + "fileSize": 5223957293, + "optimizationPrecision": "int4", + "contextWindow": 8192, + "description": "Chat with Gemma 7b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Gemma 7b", + "id": "gemma-7b-int8-ov", + "fileSize": 9228794075, + "optimizationPrecision": "int8", + "contextWindow": 8192, + "description": "Chat with Gemma 7b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Gemma 7b It", + "id": "gemma-7b-it-int8-ov", + "fileSize": 9228795991, + "optimizationPrecision": "int8", + "contextWindow": 8192, + "description": "Chat with Gemma 7b It", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Gemma 7b It", + "id": "gemma-7b-it-fp16-ov", + "fileSize": 18419689774, + "optimizationPrecision": "fp16", + "contextWindow": 8192, + "description": "Chat with Gemma 7b It", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Gemma 7b It", + "id": "gemma-7b-it-int4-ov", + "fileSize": 5223959210, + "optimizationPrecision": "int4", + "contextWindow": 8192, + "description": "Chat with Gemma 7b It", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Bloomz 1b1", + "id": "bloomz-1b1-fp16-ov", + "fileSize": 2322177211, + "optimizationPrecision": "fp16", + "contextWindow": 0, + "description": "Chat with Bloomz 1b1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Bloomz 1b1", + "id": "bloomz-1b1-int4-ov", + "fileSize": 812344015, + "optimizationPrecision": "int4", + "contextWindow": 0, + "description": "Chat with Bloomz 1b1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Bloomz 3b", + "id": "bloomz-3b-int8-ov", + "fileSize": 3267500581, + "optimizationPrecision": "int8", + "contextWindow": 0, + "description": "Chat with Bloomz 3b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Bloomz 1b1", + "id": "bloomz-1b1-int8-ov", + "fileSize": 1184136430, + "optimizationPrecision": "int8", + "contextWindow": 0, + "description": "Chat with Bloomz 1b1", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Bloomz 3b", + "id": "bloomz-3b-int4-ov", + "fileSize": 2043570274, + "optimizationPrecision": "int4", + "contextWindow": 0, + "description": "Chat with Bloomz 3b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Bloomz 3b", + "id": "bloomz-3b-fp16-ov", + "fileSize": 6488568080, + "optimizationPrecision": "fp16", + "contextWindow": 0, + "description": "Chat with Bloomz 3b", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Codegen 2B Multi", + "id": "codegen-2B-multi-int8-ov", + "fileSize": 2995146381, + "optimizationPrecision": "int8", + "contextWindow": 2048, + "description": "Chat with Codegen 2B Multi", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Codegen 2B Multi", + "id": "codegen-2B-multi-fp16-ov", + "fileSize": 5980001146, + "optimizationPrecision": "fp16", + "contextWindow": 2048, + "description": "Chat with Codegen 2B Multi", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Codegen 2B Multi", + "id": "codegen-2B-multi-int4-ov", + "fileSize": 1696055110, + "optimizationPrecision": "int4", + "contextWindow": 2048, + "description": "Chat with Codegen 2B Multi", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Codegen 6B Multi", + "id": "codegen-6B-multi-int4-ov", + "fileSize": 4165776649, + "optimizationPrecision": "int4", + "contextWindow": 2048, + "description": "Chat with Codegen 6B Multi", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Codegen 6B Multi", + "id": "codegen-6B-multi-fp16-ov", + "fileSize": 15149850695, + "optimizationPrecision": "fp16", + "contextWindow": 2048, + "description": "Chat with Codegen 6B Multi", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Codegen 6B Multi", + "id": "codegen-6B-multi-int8-ov", + "fileSize": 7601603664, "optimizationPrecision": "int8", "contextWindow": 2048, - "description": "Chat with RedPajama INCITE Instruct 3B V1 model", - "task": "text-generation" + "description": "Chat with Codegen 6B Multi", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Phi 3.5 Mini Instruct", + "id": "Phi-3.5-mini-instruct-fp16-ov", + "fileSize": 8211750487, + "optimizationPrecision": "fp16", + "contextWindow": 131072, + "description": "Chat with Phi 3.5 Mini Instruct", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Phi 3.5 Mini Instruct", + "id": "Phi-3.5-mini-instruct-int8-ov", + "fileSize": 4110193740, + "optimizationPrecision": "int8", + "contextWindow": 131072, + "description": "Chat with Phi 3.5 Mini Instruct", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Phi 3.5 Mini Instruct", + "id": "Phi-3.5-mini-instruct-int4-ov", + "fileSize": 2242029798, + "optimizationPrecision": "int4", + "contextWindow": 131072, + "description": "Chat with Phi 3.5 Mini Instruct", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Gemma 2 9b It", + "id": "gemma-2-9b-it-int4-ov", + "fileSize": 5698219462, + "optimizationPrecision": "int4", + "contextWindow": 8192, + "description": "Chat with Gemma 2 9b It", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Gemma 2 9b It", + "id": "gemma-2-9b-it-int8-ov", + "fileSize": 9992851184, + "optimizationPrecision": "int8", + "contextWindow": 8192, + "description": "Chat with Gemma 2 9b It", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" + }, + { + "name": "Gemma 2 9b It", + "id": "gemma-2-9b-it-fp16-ov", + "fileSize": 19924637310, + "optimizationPrecision": "fp16", + "contextWindow": 8192, + "description": "Chat with Gemma 2 9b It", + "task": "text-generation", + "author": "OpenVINO", + "collection": "llm-6687aaa2abca3bbcec71a9bd" } ] } diff --git a/images/banner.png b/images/banner.png new file mode 100644 index 00000000..f27dcb25 Binary files /dev/null and b/images/banner.png differ diff --git a/images/clear.svg b/images/clear.svg index a9f643c0..a7fc7e39 100644 --- a/images/clear.svg +++ b/images/clear.svg @@ -1,2 +1,4 @@ - - \ No newline at end of file + + + \ No newline at end of file diff --git a/images/copy.svg b/images/copy.svg index 7a23f242..d2b20a7e 100644 --- a/images/copy.svg +++ b/images/copy.svg @@ -1,31 +1,4 @@ - - - - - S Copy 18 N - - - - - - - - - - - - - - - - - - - - - + + + diff --git a/images/drop_light.svg b/images/drop_light.svg new file mode 100644 index 00000000..db8d6d42 --- /dev/null +++ b/images/drop_light.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/network.svg b/images/network.svg index d9d0aa05..f9764d43 100644 --- a/images/network.svg +++ b/images/network.svg @@ -1,11 +1,4 @@ - - - S SocialNetwork 18 N diff --git a/images/playground.svg b/images/playground.svg new file mode 100644 index 00000000..ef094789 --- /dev/null +++ b/images/playground.svg @@ -0,0 +1,4 @@ + + + + diff --git a/images/stats.svg b/images/stats.svg index cd039b5b..7fef770d 100644 --- a/images/stats.svg +++ b/images/stats.svg @@ -1,9 +1,4 @@ - - - - - - - - - \ No newline at end of file + + + + diff --git a/images/user.svg b/images/user.svg index 01dc6b59..f5bb8944 100644 --- a/images/user.svg +++ b/images/user.svg @@ -1,11 +1,4 @@ - - - S User 18 N diff --git a/integration_test/app_test.dart b/integration_test/app_test.dart index 2c6bd98f..e3df09e0 100644 --- a/integration_test/app_test.dart +++ b/integration_test/app_test.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:inference/main.dart'; import 'package:integration_test/integration_test.dart'; @@ -6,29 +5,28 @@ import 'package:integration_test/integration_test.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - testWidgets('Download model from HF', (tester) async { - final originalOnError = FlutterError.onError!; + //testWidgets('Download model from HF', (tester) async { + // const app = App(); + // await tester.pumpWidget(app); - const app = App(); - await tester.pumpWidget(app); + // await tester.tap(find.text('Import model')); + // await tester.pumpAndSettle(); - FlutterError.onError = originalOnError; + // await tester.tap(find.text('Hugging Face')); + // await tester.pumpAndSettle(); - await tester.tap(find.text('Import Model')); - await tester.pumpAndSettle(); + // final searchBarFinder = find.bySemanticsLabel('Find a model').first; + // await tester.tap(searchBarFinder, warnIfMissed: false); + // await tester.pumpAndSettle(); + // await tester.enterText(searchBarFinder, 'tiny'); + // await tester.pumpAndSettle(); - await tester.tap(find.text('Huggingface')); - await tester.pumpAndSettle(); + // await tester.tap(find.text('TinyLlama 1.1B Chat V1.0').first); + // await tester.pumpAndSettle(); + // await tester.tap(find.text('Import selected model')); + // await tester.pumpFrames(app, const Duration(seconds: 1)); + // expect(find.textContaining(RegExp(r'^[1-9][\d,]* MB$')), findsNWidgets(2)); - await tester.tap(find.bySemanticsLabel('Search by name')); - await tester.pumpAndSettle(); - await tester.enterText(find.bySemanticsLabel('Search by name'), 'tiny'); - await tester.pumpAndSettle(); - - await tester.tap(find.text('TinyLlama-1.1B-Chat-v1.0-int4-ov')); - await tester.pumpAndSettle(); - await tester.tap(find.text('Add model')); - await tester.pumpFrames(app, const Duration(seconds: 1)); - expect(find.textContaining(RegExp(r'^[1-9]\d* MB$')), findsNWidgets(2)); - }); -} \ No newline at end of file + // await tester.pumpAndSettle(); + //}); +} diff --git a/lib/example_graph.dart b/lib/example_graph.dart deleted file mode 100644 index 6b2b588e..00000000 --- a/lib/example_graph.dart +++ /dev/null @@ -1,46 +0,0 @@ -const String faceDetectionExampleGraph = """ -output_stream : "output" - -node { - calculator : "OpenVINOInferenceAdapterCalculator" - output_side_packet : "INFERENCE_ADAPTER:adapter" - node_options: { - [type.googleapis.com/mediapipe.OpenVINOInferenceAdapterCalculatorOptions] { - model_path: "/data/omz_models/intel/face-detection-retail-0004/face-detection-retail-0004.xml" - } - } -} - -node { - calculator : "VideoInputCalculator" - output_stream: "IMAGE:input_image" -} - -node { - calculator : "DetectionCalculator" - input_side_packet : "INFERENCE_ADAPTER:adapter" - input_stream : "IMAGE:input_image" - output_stream: "INFERENCE_RESULT:inference_detections" -} - -node { - calculator : "OverlayCalculator" - input_stream : "IMAGE:input_image" - input_stream : "INFERENCE_RESULT:inference_detections" - output_stream: "IMAGE:output" - node_options: { - [type.googleapis.com/mediapipe.OverlayCalculatorOptions] { - labels: { - id: "face" - name: "face" - color: "#f7dab3ff" - is_empty: false - } - - stroke_width: 2 - opacity: 0.4 - font_size: 1.0 - } - } -} -"""; diff --git a/lib/header.dart b/lib/header.dart deleted file mode 100644 index bede01c4..00000000 --- a/lib/header.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:flutter_svg/svg.dart'; - -class Header extends StatelessWidget implements PreferredSizeWidget { - final bool showBack; - final void Function(BuildContext context)? onBack; - const Header(this.showBack, {this.onBack, super.key}); - - - @override - Widget build(BuildContext context) { - return Column( - children: [ - SizedBox( - height: 88, - child: Stack( - children: [ - Container( - padding: const EdgeInsets.only(left: 30), - height: 64, - color: Theme.of(context).colorScheme.secondary, - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - if(showBack) Padding( - padding: const EdgeInsets.only(right: 5), - child: IconButton( - color: Colors.white, - icon: const Icon(Icons.arrow_back), - onPressed: () { - if(onBack != null) { - onBack!(context); - } else { - context.go('/'); - } - } - ), - ), - Padding( - padding: const EdgeInsets.only(right: 10.0, top: 2), - child: SvgPicture.asset("images/openvino_logo.svg"), - ), - const Text("Test Drive", style: TextStyle( - color: Colors.white, - fontSize: 20, - )), - ], - ), - ), - SvgPicture.asset("images/bit.svg"), - ] - ), - ), - ], - ); - } - - @override - Size get preferredSize => const Size.fromHeight(88); -} diff --git a/lib/import/import_page.dart b/lib/import/import_page.dart deleted file mode 100644 index 5eaab894..00000000 --- a/lib/import/import_page.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:inference/header.dart'; -import 'package:inference/import/public_model.dart'; - -class ImportPage extends StatefulWidget { - const ImportPage({super.key}); - - @override - State createState() => _ImportPageState(); -} - -class _ImportPageState extends State with TickerProviderStateMixin { - late TabController _tabController; - - @override - void initState() { - super.initState(); - _tabController = TabController(length: 3, animationDuration: Duration.zero, vsync: this); - } - - @override - void dispose() { - _tabController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return const Scaffold( - appBar: Header(false), - body: Padding( - padding: EdgeInsets.symmetric(horizontal: 30.0), - child: PublicModelPage() - ), - ); - } -} diff --git a/lib/import/optimization_filter_button.dart b/lib/import/optimization_filter_button.dart deleted file mode 100644 index 98efce6f..00000000 --- a/lib/import/optimization_filter_button.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:inference/providers/project_filter_provider.dart'; - -class OptimizationFilterButton extends StatelessWidget { - - final String name; - final ProjectFilterProvider filter; - const OptimizationFilterButton(this.name, this.filter, {super.key}); - - @override - Widget build(BuildContext context) { - return Card( - child: Padding( - padding: const EdgeInsets.only(right: 12.0), - child: Row( - children: [ - Checkbox(value: filter.optimizations.contains(name), onChanged: (val) { - if (val ?? false) { - filter.addOptimization(name); - } else { - filter.removeOptimization(name); - } - }), - Text(name), - ], - ), - ), - ); - } -} diff --git a/lib/import/public_model.dart b/lib/import/public_model.dart deleted file mode 100644 index ce2bd065..00000000 --- a/lib/import/public_model.dart +++ /dev/null @@ -1,323 +0,0 @@ -import 'package:dio/dio.dart'; -import 'package:flutter/material.dart'; -import 'package:inference/import/optimization_filter_button.dart'; -import 'package:inference/projects/task_type_filter.dart'; -import 'package:inference/providers/project_filter_provider.dart'; -import 'package:inference/providers/project_provider.dart'; -import 'package:inference/public_model_info.dart'; -import 'package:inference/public_models.dart'; -import 'package:inference/searchbar.dart'; -import 'package:inference/theme.dart'; -import 'package:inference/utils/dialogs.dart'; -import 'package:provider/provider.dart'; -import 'package:shimmer/shimmer.dart'; -import 'package:go_router/go_router.dart'; - -class PublicModelPage extends StatefulWidget { - const PublicModelPage({super.key}); - - @override - State createState() => _PublicModelPageState(); -} - -class _PublicModelPageState extends State { - List? models; - - PublicModelInfo? selectedModelForImport; - - void loadModels() async { - try { - final publicModels = await getPublicModels(); - setState(() { - models = publicModels; - }); - } on DioException catch(ex) { - if (ex.type == DioExceptionType.connectionError) { - if (context.mounted) { - errorDialog(context, "Connection error","Unable to connect to HuggingFace to load the OpenVINO model collections.\nPlease disable your proxy or VPN and try again."); - } - } - } - - } - - @override - void initState() { - super.initState(); - loadModels(); - } - - List buildList(ProjectFilterProvider filter) { - if (models == null) { - return const [ - GhostProjectItem(), - GhostProjectItem(), - GhostProjectItem(), - GhostProjectItem(), - GhostProjectItem(), - GhostProjectItem(), - GhostProjectItem(), - GhostProjectItem(), - ]; - } - - final filteredModels = filter.applyFilterOnPublicModelInfo(models!); - - return filteredModels.map((model) { - return PublicModelItem(model, - key: ValueKey(model), - isSelected: selectedModelForImport == model, - onToggle: (selected) { - setState(() { - if (selected) { - selectedModelForImport = model; - } else { - selectedModelForImport = null; - } - }); - }, - ); - }).toList(); - } - - @override - Widget build(BuildContext context) { - return ChangeNotifierProvider( - create: (_) => ProjectFilterProvider(), - child: Consumer(builder: (context, filter, child) { - return Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Row( - children: [ - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Padding( - padding: const EdgeInsets.only(left: 3, bottom: 8.0, top: 8.0, right: 8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - GetiSearchBar( - onChange: (value) => filter.name = value, - ), - const Padding( - padding: EdgeInsets.only(left: 32.0), - child: Text("Optimization: "), - ), - OptimizationFilterButton("int4", filter), - OptimizationFilterButton("int8", filter), - OptimizationFilterButton("fp16", filter), - ], - ), - ), - Expanded( - child: CustomScrollView( - primary: false, - slivers: [ - SliverPadding( - padding: const EdgeInsets.all(3), - sliver: SliverGrid.extent( - crossAxisSpacing: 10, - mainAxisSpacing: 10, - maxCrossAxisExtent: 310, - childAspectRatio: 1.5, - children: buildList(filter) - ) - ) - ] - ), - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 30.0, horizontal: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Padding( - padding: const EdgeInsets.only(right: 8.0), - child: ElevatedButton( - style: const ButtonStyle( - elevation: WidgetStatePropertyAll(0), - backgroundColor: WidgetStatePropertyAll(intelGray) - ), - onPressed: () { - setState(() { - context.pop(); - }); - }, - child: const Text("Cancel") - ), - ), - - ElevatedButton( - style: ButtonStyle( - elevation: const WidgetStatePropertyAll(0), - backgroundColor: (selectedModelForImport == null - ? const WidgetStatePropertyAll(intelGray) - : null - ) - ), - onPressed: () { - if (selectedModelForImport != null) { - final projectsProvider = Provider.of(context, listen: false); - PublicModelInfo.convertToProject(selectedModelForImport!).then((project) { - projectsProvider.addProject(project); - context.go('/inference', extra: project); - }); - } - }, - child: const Text("Add model") - ), - ], - ), - ), - ], - ), - ), - ], - ), - ); - } - ), - ); - } -} - - -class GhostProjectItem extends StatelessWidget { - const GhostProjectItem({super.key}); - - @override - Widget build(BuildContext context) { - return ClipRRect( - borderRadius: BorderRadius.circular(8.0), - child: Opacity( - opacity: 1.0, - child: ConstrainedBox( - constraints: const BoxConstraints.expand(height: 136), - child: Shimmer.fromColors( - baseColor: Theme.of(context).colorScheme.surface, - highlightColor: Theme.of(context).colorScheme.onSurfaceVariant, - child: Container( - color: Theme.of(context).colorScheme.surface, - ) - ), - ), - ) - ); - } -} - -class PublicModelItem extends StatefulWidget { - final PublicModelInfo model; - final Function onToggle; - final bool isSelected; - const PublicModelItem(this.model, {required this.onToggle, this.isSelected = false, super.key}); - - @override - State createState() => _PublicModelItemState(); -} - -class _PublicModelItemState extends State { - bool hovered = false; - - void onHover(bool? val) { - setState(() { - hovered = val ?? false; - }); - } - - void onTap() { - widget.onToggle(!widget.isSelected); - } - - Color backgroundColor(BuildContext context) { - final scheme = Theme.of(context).colorScheme; - if (hovered) { - return scheme.onSurfaceVariant; - } else { - return scheme.surface; - } - } - - Color borderColor(BuildContext context) { - if (widget.isSelected) { - return intelBlue; - } else { - return backgroundColor(context); - } - } - - double borderWidth(BuildContext context) { - if (widget.isSelected) { - return 2; - } else { - return 0; - } - } - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.only(top: 8, bottom: 8), - child: Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.0), - side: BorderSide(width: borderWidth(context), color: borderColor(context)) - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(8.0), - child: InkWell( - splashFactory: NoSplash.splashFactory, - borderRadius: BorderRadius.circular(8.0), - onHover: (val) => onHover(val), - onTap: () => onTap(), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - height: 110, - decoration: BoxDecoration( - image: DecorationImage( - image: widget.model.thumbnail.image, - fit: BoxFit.cover), - ), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - widget.model.name, - overflow: TextOverflow.ellipsis, - style: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - fontSize: 12, - ) - ), - //Text(formatter.format(DateTime.parse(widget.model.lastModified))), - //Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text("Likes: ${widget.model.likes}"), - // Text("Downloads: ${widget.model.downloads}"), - // ], - //), - ] - ), - ), - ) - ], - ), - ), - ) - ) - ); - } -} diff --git a/lib/importers/manifest_importer.dart b/lib/importers/manifest_importer.dart new file mode 100644 index 00000000..5c0d3f82 --- /dev/null +++ b/lib/importers/manifest_importer.dart @@ -0,0 +1,124 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:inference/project.dart'; +import 'package:inference/public_model_info.dart'; +import 'package:inference/utils/get_public_thumbnail.dart'; +import 'package:inference/utils.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:uuid/uuid.dart'; + +class Model { + final String name; + final String id; + final int fileSize; + final String optimizationPrecision; + final int contextWindow; + final String description; + final String task; + + Model({ + required this.name, + required this.id, + required this.fileSize, + required this.optimizationPrecision, + required this.contextWindow, + required this.description, + required this.task, + }); + + Image get thumbnail { + return getThumbnail(id); + } + + String get kind => task == 'text-generation' ? 'llm' : 'other'; + + String get readableFileSize { + return fileSize.toDouble().readableFileSize(); + } + + factory Model.fromJson(Map json) { + return Model( + name: json['name'], + id: json['id'], + fileSize: json['fileSize'], + optimizationPrecision: json['optimizationPrecision'], + contextWindow: json['contextWindow'], + description: json['description'], + task: json['task'], + ); + } + + Future convertToProject() async { + final directory = await getApplicationSupportDirectory(); + final projectId = const Uuid().v4(); + final storagePath = platformContext.join(directory.path, projectId.toString()); + await Directory(storagePath).create(recursive: true); + final projectType = parseProjectType(task); + + final project = PublicProject( + projectId, + "OpenVINO/$id", + "1.0.0", + name, + DateTime.now().toIso8601String(), + projectType, + storagePath, + thumbnail, + PublicModelInfo( + id, + DateTime.now().toIso8601String(), + 0, + 0, + task, + const Collection("https://huggingface.co/api/collections/OpenVINO/llm-6687aaa2abca3bbcec71a9bd", "", "text"), + ), + ); + + project.tasks.add( + Task( + genUUID(), + task, + task, + [], + null, + [], + "", + "", + ), + ); + + return project; + } +} + +class ManifestImporter { + final String manifestPath; + List popularModels = []; + List allModels = []; + + ManifestImporter(this.manifestPath); + + Future loadManifest() async { + final contents = await rootBundle.loadString(manifestPath); + final jsonData = jsonDecode(contents); + + popularModels = (jsonData['popular_models'] as List) + .map((modelJson) => Model.fromJson(modelJson)) + .toList(); + + allModels = (jsonData['all_models'] as List) + .map((modelJson) => Model.fromJson(modelJson)) + .toList(); + } + + List getPopularModels() { + return popularModels; + } + + List getAllModels() { + return allModels; + } +} diff --git a/lib/inference/batch_inference.dart b/lib/inference/batch_inference.dart deleted file mode 100644 index e0a59d60..00000000 --- a/lib/inference/batch_inference.dart +++ /dev/null @@ -1,507 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; -import 'dart:typed_data'; - -import 'package:csv/csv.dart'; -import 'package:desktop_drop/desktop_drop.dart'; -import 'package:file_picker/file_picker.dart'; -import 'package:flutter/material.dart'; -import 'package:inference/inference/device_selector.dart'; -import 'package:inference/interop/openvino_bindings.dart'; -import 'package:inference/providers/image_inference_provider.dart'; -import 'package:inference/theme.dart'; -import 'package:mime/mime.dart'; -import 'package:path/path.dart'; -import 'package:provider/provider.dart'; - -bool isImage(String path) { - final mimeType = lookupMimeType(path); - if (mimeType == null) { - return false; - } - return mimeType.startsWith('image/'); -} - - -bool pathIsValid(String path) { - // Directory.exists will return false if the file is not a folder. - return Directory(path).existsSync(); -} - -class Progress { - int current = 0; - final int total; - - Progress(this.total); - - double percentage() { - return current.toDouble() / total; - } -} - - -class BatchInference extends StatefulWidget { - const BatchInference({super.key}); - - @override - State createState() => _BatchInferenceState(); -} - -class _BatchInferenceState extends State { - - String sourceFolder = ""; - String destinationFolder = ""; - bool forceStop = false; - Progress? progress; - - bool get isRunning { - if (progress == null) { - return false; - } - - if (forceStop) { - return false; - } - - return progress!.current < progress!.total; - } - - bool get canProcess => - pathIsValid(sourceFolder) && pathIsValid(destinationFolder) && - serializationOutput.any(); - - SerializationOutput serializationOutput = SerializationOutput(overlay: true); - - void processFolder(BuildContext context, ImageInferenceProvider inference) async { - final platformContext = Context(style: Style.platform); - final dir = Directory(sourceFolder); - final listener = dir.list(recursive: true); - - final list = await listener.toList(); - setState(() { - progress = Progress(list.where((item) => isImage(item.path)).length); - forceStop = false; - }); - - List> rows = []; - const encoder = JsonEncoder.withIndent(" "); - const converter = CsvToListConverter(); - inference.lock(); - - for (final file in list) { - if (forceStop) { - break; - } - if (isImage(file.path)) { - final outputFilename = platformContext.basename(file.path); - Uint8List imageData = File(file.path).readAsBytesSync(); - final inferenceResult = await inference.infer(imageData, serializationOutput); - await Future.delayed(Duration.zero); // For some reason ui does not update even though it's running in Isolate. This gives the UI time to run that code. - final outputPath = platformContext.join(destinationFolder, outputFilename); - if (serializationOutput.overlay) { - final outputFile = File(outputPath); - final decodedImage = base64Decode(inferenceResult.overlay!); - outputFile.writeAsBytes(decodedImage); - } - if (serializationOutput.csv) { - var csvOutput = converter.convert(inferenceResult.csv); - rows.addAll(csvOutput.map((row) { - row.insert(0, outputFilename); - return row; - })); - } - if (serializationOutput.json) { - final outputFile = File(setExtension(outputPath, ".json")); - outputFile.writeAsString(encoder.convert(inferenceResult.json)); - } - setState(() { - progress!.current += 1; - }); - } - } - inference.unlock(); - - if (serializationOutput.csv) { - List columns = ["filename", "label_name", "label_id", "probability", "shape_type", "x", "y", "width", "height", "area", "angle"]; - rows.insert(0, columns); - const converter = ListToCsvConverter(); - final outputPath = platformContext.join(destinationFolder, "predictions.csv"); - File(outputPath).writeAsStringSync(converter.convert(rows)); - } - } - - void stop() { - setState((){ - forceStop = true; - }); - } - - @override - Widget build(BuildContext context) { - return Consumer( - builder: (context, inference, child) { - return Padding( - padding: const EdgeInsets.only(top: 48.0), - child: Container( - color: Theme.of(context).colorScheme.surfaceContainer, - padding: const EdgeInsets.all(30), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - FolderRow("Source folder", - initialValue: sourceFolder, - enabled: !isRunning, - onSubmit: (path) { - setState(() { - sourceFolder = path; - }); - }), - FolderRow("Destination folder", - initialValue: destinationFolder, - enabled: !isRunning, - onSubmit: (path) { - setState(() { - destinationFolder = path; - }); - }), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Padding( - padding: EdgeInsets.only(bottom: 3.0), - child: Text("Outputs"), - ), - SwitchRow("Overlay image", - onChange: (value) { - setState(() { - serializationOutput.overlay = value; - }); - }, - initialValue: serializationOutput.overlay, - ), - SwitchRow("CSV", - onChange: (value) { - setState(() { - serializationOutput.csv = value; - }); - }, - initialValue: serializationOutput.csv, - ), - SwitchRow("JSON", - onChange: (value) { - setState(() { - serializationOutput.json = value; - }); - }, - initialValue: serializationOutput.json, - ), - ], - ), - const DeviceSelector(), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 20), - child: BatchProgressButton( - isRunning: isRunning, - enabled: canProcess && inference.isReady, - onStart: () { - processFolder(context, inference); - }, - onStop: () => stop(), - ), - ), - - BatchProgress(progress), - ], - ), - ), - ); - } - ); - } -} - -class BatchProgressButton extends StatelessWidget { - final bool isRunning; - final bool enabled; - final void Function() onStart; - final void Function() onStop; - - const BatchProgressButton({required this.onStart, required this.onStop, this.isRunning = false, this.enabled = true, super.key}); - - @override - Widget build(BuildContext context) { - if (isRunning) { - return ElevatedButton( - onPressed: onStop, - child: const Text("Stop")); - } - - if (!enabled) { - return ElevatedButton( - style: const ButtonStyle( - backgroundColor: MaterialStatePropertyAll(intelGrayLight), - elevation: MaterialStatePropertyAll(0), - ), - onPressed: () {}, - child: const Text("Start")); - } - - return ElevatedButton( - onPressed: onStart, - child: const Text("Start")); - } - -} - -class BatchProgress extends StatelessWidget { - final Progress? progress; - const BatchProgress(this.progress, {super.key}); - - @override - Widget build(BuildContext context) { - return Builder( - builder: (context) { - if (progress == null) { - return const SizedBox.shrink(); - } - - return SizedBox( - width: 300, - child: Column( - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text("Inference progress"), - Text("${progress!.current}/${progress!.total}"), - ]), - ), - LinearProgressIndicator( - value: progress!.percentage(), - color: intelBlueLight, - backgroundColor: intelGrayLight, - minHeight: 8, - borderRadius: BorderRadius.circular(4), - ) - ] - ) - ); - } - ); - } -} - -class SwitchRow extends StatefulWidget { - final String label; - final void Function(bool) onChange; - final bool initialValue; - const SwitchRow(this.label, {required this.onChange, this.initialValue = false, super.key}); - - @override - State createState() => _SwitchRowState(); -} - -class _SwitchRowState extends State { - bool switchState = false; - - @override - void initState() { - // TODO: implement initState - super.initState(); - switchState = widget.initialValue; - } - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.only(bottom: 8.0), - child: Row( - children: [ - SizedBox( - width: 30, - height: 20, - child: FittedBox( - fit: BoxFit.fill, - child: Switch.adaptive( - value: switchState, - activeColor: intelGrayReallyDark, - activeTrackColor: lightGray, - onChanged: (value) { - setState(() { switchState = value; }); - widget.onChange(value); - }, - ), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: Text(widget.label), - ), - ], - ), - ); - } -} - -class FolderRow extends StatefulWidget { - final String label; - final bool enabled; - final String initialValue; - final void Function(String) onSubmit; - const FolderRow(this.label, - {required this.onSubmit, this.initialValue = "", this.enabled = true, super.key}); - - @override - State createState() => _FolderRowState(); -} - -class _FolderRowState extends State { - bool _showReleaseMessage = false; - bool pathSet = false; - bool isValid = false; - - final controller = TextEditingController(); - final platformContext = Context(style: Style.platform); - - @override - void initState() { - super.initState(); - controller.text = widget.initialValue; - isValid = pathIsValid(controller.text); - } - - void showReleaseMessage() { - setState(() => _showReleaseMessage = true); - } - - void hideReleaseMessage() { - setState(() => _showReleaseMessage = false); - } - - void handleDrop(DropDoneDetails details) { - if (details.files.isNotEmpty) { - setPath(details.files[0].path); - } - } - - void setPath(String path) { - if (pathIsValid(path)) { - controller.text = path; - widget.onSubmit(path); - setState(() { - pathSet = true; - isValid = true; - }); - } else { - //TODO show user error that a folder must be selected - } - } - - @override - void dispose() { - // TODO: implement dispose - super.dispose(); - controller.dispose(); - } - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: DropTarget( - onDragDone: (details) => handleDrop(details), - onDragExited: (_) => hideReleaseMessage(), - onDragEntered: (_) => showReleaseMessage(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 3.0), - child: Text(widget.label), - ), - Row( - children: [ - SizedBox( - width: 300, - height: 30, - child: TextField( - onChanged: (path) { - setState(() { - isValid = pathIsValid(path); - //Submit regardless. Path can be invalid, but that's less confusing to the user. - widget.onSubmit(path); - pathSet = isValid; - }); - }, - enabled: widget.enabled, - controller: controller, - textAlign: TextAlign.start, - style: const TextStyle ( - color: textColor, - fontSize: 10, - ), - decoration: InputDecoration( - contentPadding: const EdgeInsets.only(left: 10, bottom: 0), - hintText: (_showReleaseMessage - ? "Release..." - : "Drop ${widget.label.toLowerCase()} in"), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: (isValid ? Colors.green : Colors.red), - )), - ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20.0), - child: FolderButton( - enabled: widget.enabled, - text: (pathSet ? "Change" : "Select"), - onSelect: setPath, - ), - ) - ], - ), - ], - ), - ), - ); - } -} - -class FolderButton extends StatelessWidget { - final String text; - final void Function(String) onSelect; - final bool enabled; - const FolderButton({required this.onSelect, required this.text, this.enabled = true, super.key}); - - void showUploadMenu() async { - final result = await FilePicker.platform.getDirectoryPath(); - if (result != null) { - onSelect(result.toString()); - } - } - - @override - Widget build(BuildContext context) { - if (!enabled) { - return ElevatedButton.icon( - icon: const Icon(Icons.folder), - onPressed: () {}, - style: const ButtonStyle( - elevation: MaterialStatePropertyAll(0), - backgroundColor: MaterialStatePropertyAll(intelGrayLight), - ), - label: Text(text), - ); - } - - return OutlinedButton.icon( - icon: const Icon(Icons.folder), - onPressed: () => showUploadMenu(), - label: Text(text), - ); - } -} diff --git a/lib/inference/camera_page.dart b/lib/inference/camera_page.dart deleted file mode 100644 index 0bd26cdc..00000000 --- a/lib/inference/camera_page.dart +++ /dev/null @@ -1,109 +0,0 @@ -import 'dart:async'; -import 'dart:typed_data'; -import 'dart:ui' as ui; -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:inference/providers/image_inference_provider.dart'; -import 'package:provider/provider.dart'; - -Future createImage(Uint8List bytes) async { - final Completer completer = Completer(); - ui.decodeImageFromList(bytes, - (ui.Image img) { - completer.complete(img); - }, - ); - return completer.future; -} -class CameraPage extends StatefulWidget { - final ImageInferenceProvider inferenceProvider; - - const CameraPage(this.inferenceProvider, {super.key}); - @override - State createState() => _CameraPageState(); -} - - -class _CameraPageState extends State { - ui.Image? image; - - ImageInferenceProvider get inferenceProvider => widget.inferenceProvider; - - void openCamera() { - inferenceProvider.openCamera(0); - inferenceProvider.setListener((output) { - print(output); - createImage(base64Decode(output.overlay!)).then((frame) { - if (mounted) { - setState(() { - image = frame; - }); - } - }); - }); - } - - - @override - void initState() { - super.initState(); - openCamera(); - } - - @override - void dispose() { - inferenceProvider.closeCamera(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Expanded( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: LayoutBuilder( - builder: (context, constraints) { - if (image == null) { - return Container(); - } - - - return SizedBox( - width: 200, - height: 200, - child: CustomPaint( - painter: ImagePainter(image!), - size: Size(100, 200), - child: Container(), - ) -, - ); - } - ), - ), - ); - } - -} -class ImagePainter extends CustomPainter { - final ui.Image image; - ImagePainter(this.image); - - @override - void paint(Canvas canvas, Size size) { - paintImage( - canvas: canvas, - rect: Rect.fromLTWH(0, 0, size.width, size.height), - image: image, - ); - //canvas.drawImage(image, Offset.zero, Paint()); - } - - @override - bool shouldRepaint(ImagePainter oldDelegate) { - return true; - } - @override - bool shouldRebuildSemantics(ImagePainter oldDelegate) => false; -} diff --git a/lib/inference/device_selector.dart b/lib/inference/device_selector.dart deleted file mode 100644 index 8ca8e53f..00000000 --- a/lib/inference/device_selector.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:inference/providers/preference_provider.dart'; -import 'package:inference/theme.dart'; -import 'package:provider/provider.dart'; - -class DeviceSelector extends StatelessWidget { - const DeviceSelector({super.key}); - - @override - Widget build(BuildContext context) { - return Row( - children: [ - const Text("Device: "), - Consumer(builder: (context, preferences, child) { - return DropdownButton( - onChanged: (value) { - preferences.device = value!; - }, - underline: Container( - height: 0, - ), - style: const TextStyle( - fontSize: 12.0, - ), - focusColor: intelGrayDark, - padding: const EdgeInsets.symmetric(horizontal: 10), - value: preferences.device, - items: PreferenceProvider.availableDevices.map>((value) { - return DropdownMenuItem( - value: value.id, - child: Text(value.name), - ); - }).toList() - ); - } - ), - ], - ); - } -} diff --git a/lib/inference/download_page.dart b/lib/inference/download_page.dart deleted file mode 100644 index fac683be..00000000 --- a/lib/inference/download_page.dart +++ /dev/null @@ -1,124 +0,0 @@ -import 'dart:math'; - -import 'package:go_router/go_router.dart'; -import 'package:flutter/material.dart'; -import 'package:inference/header.dart'; -import 'package:inference/inference/device_selector.dart'; -import 'package:inference/inference/model_info.dart'; -import 'package:inference/project.dart'; -import 'package:inference/providers/download_provider.dart'; -import 'package:inference/providers/project_provider.dart'; -import 'package:inference/public_models.dart'; -import 'package:inference/theme.dart'; -import 'package:intl/intl.dart'; -import 'package:provider/provider.dart'; - -String formatBytes(int bytes) { - return "${NumberFormat("#,##0").format(bytes / pow(1024, 2))} MB"; -} - -class DownloadPage extends StatefulWidget { - final PublicProject project; - final Function() onDone; - const DownloadPage(this.project, {required this.onDone, super.key}); - - @override - State createState() => _DownloadPageState(); -} - -class _DownloadPageState extends State { - @override - void initState() { - super.initState(); - - startDownload(); - } - - void startDownload() async { - final downloadProvider = Provider.of(context, listen: false); - final projectProvider = Provider.of(context, listen: false); - - final files = await downloadFiles(widget.project); - - try { - await downloadProvider.queue(files, widget.project.modelInfo?.collection.token); - await getAdditionalModelInfo(widget.project); - projectProvider.completeLoading(widget.project); - widget.onDone(); - } catch(e) { - if (mounted) { - showDialog(context: context, builder: (BuildContext context) => AlertDialog( - title: Text('An error occured trying to download ${widget.project.name}'), - content: Text(e.toString()), - actions: [ - TextButton( - onPressed: () => context.go('/'), - child: const Text('Close'), - ), - ] - ), - - ); - } - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: const Header(true), - body: Padding( - padding: const EdgeInsets.only(left: 58, right: 58, bottom: 30), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - width: 250, - child: ModelInfo(widget.project), - ), - Consumer(builder: (context, downloads, child) { - final stats = downloads.stats; - return Expanded( - child: Column( - children: [ - const DeviceSelector(), - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - CircularProgressIndicator( - backgroundColor: textColor, - value: stats.percentage - ), - SizedBox( - width: 140, - child: Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text(formatBytes(stats.received), textAlign: TextAlign.end,), - const Text("/"), - Text(formatBytes(stats.total)) - ], - ), - ), - ), - const Padding( - padding: EdgeInsets.all(8.0), - child: Text("Downloading model weights"), - ) - ], - ), - ), - ], - ), - ); - }) - ], - ), - ), - ); - } -} diff --git a/lib/inference/image_inference_page.dart b/lib/inference/image_inference_page.dart deleted file mode 100644 index e9b035c5..00000000 --- a/lib/inference/image_inference_page.dart +++ /dev/null @@ -1,126 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:inference/header.dart'; -import 'package:inference/inference/batch_inference.dart'; -import 'package:inference/inference/live_inference.dart'; -import 'package:inference/inference/model_info.dart'; -import 'package:inference/project.dart'; -import 'package:inference/providers/image_inference_provider.dart'; -import 'package:inference/providers/project_provider.dart'; -import 'package:inference/providers/preference_provider.dart'; -import 'package:inference/utils/dialogs.dart'; -import 'package:provider/provider.dart'; - -class ImageInferencePage extends StatefulWidget { - final Project project; - const ImageInferencePage(this.project, {super.key}); - - @override - State createState() => _ImageInferencePageState(); -} - -class _ImageInferencePageState extends State - with TickerProviderStateMixin { - late TabController _tabController; - - - void onBack(BuildContext context) { - final inference = Provider.of(context, listen: false); - if (inference.isLocked) { - showDialog( - context: context, - builder: (BuildContext context) => AlertDialog( - title: const Text('Batch inference'), - content: const Text('Batch inference is running currently.'), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context, 'Cancel'), - child: const Text('Cancel'), - ), - ], - ) - ); - } else { - context.go('/'); - } - } - - @override - void initState() { - super.initState(); - _tabController = TabController(length: 2, animationDuration: Duration.zero, vsync: this); - } - - @override - void dispose() { - _tabController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return ChangeNotifierProxyProvider( - lazy: false, - create: (_) { - final device = Provider.of(context, listen: false).device; - return ImageInferenceProvider(widget.project, device)..init().catchError(onExceptionDialog(context)); - }, - update: (_, preferences, imageInferenceProvider) { - if (imageInferenceProvider != null && imageInferenceProvider.device == preferences.device) { - return imageInferenceProvider; - } - return ImageInferenceProvider(widget.project, preferences.device)..init().catchError(onExceptionDialog(context)); - }, - child: Scaffold( - appBar: Header(true, onBack: (context) => onBack(context)), - body: Padding( - padding: const EdgeInsets.only(left: 58, right: 58, bottom: 30), - child: Consumer(builder: (context, projects, child) { - return Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ModelInfo(widget.project, children: [ - PropertyItem( - name: "Task", - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: widget.project.tasks.map((task) => PropertyValue(task.name)).toList() - ) - ), - ]), - ( - Expanded( - child: Padding( - padding: const EdgeInsets.only(right: 35, left: 35), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - TabBar( - isScrollable: true, - tabAlignment: TabAlignment.start, - controller: _tabController, - tabs: const [ - Tab(text: "Live inference"), - Tab(text: "Batch inference"), - ], - ), - Expanded( - child: TabBarView( - controller: _tabController, - children: [ - LiveInference(widget.project), - const BatchInference(), - ]), - ) - ], - ), - ), - ) - ) - ], - ); - }), - ), - )); - } -} diff --git a/lib/inference/inference_page.dart b/lib/inference/inference_page.dart deleted file mode 100644 index 10b5cd68..00000000 --- a/lib/inference/inference_page.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:inference/inference/download_page.dart'; -import 'package:inference/inference/image_inference_page.dart'; -import 'package:inference/inference/text_inference_page.dart'; -import 'package:inference/inference/text_to_image_inference_page.dart'; -import 'package:inference/project.dart'; -import 'package:inference/providers/download_provider.dart'; -import 'package:provider/provider.dart'; - -class InferencePage extends StatefulWidget { - final Project project; - const InferencePage(this.project, {super.key}); - - @override - State createState() => _InferencePageState(); -} - -class _InferencePageState extends State { - @override - Widget build(BuildContext context) { - if (widget.project.isDownloaded) { - switch(widget.project.type){ - case ProjectType.image: - return ImageInferencePage(widget.project); - case ProjectType.text: - return TextInferencePage(widget.project); - case ProjectType.textToImage: - return TextToImageInferencePage(widget.project); - case ProjectType.speech: - return Container(); - } - } else { - return ChangeNotifierProvider( - create: (_) => DownloadProvider(widget.project), - child: DownloadPage(widget.project as PublicProject, - onDone: () => setState(() {}), //trigger rerender. - ) - ); - } - } -} diff --git a/lib/inference/live_inference.dart b/lib/inference/live_inference.dart deleted file mode 100644 index 0b464165..00000000 --- a/lib/inference/live_inference.dart +++ /dev/null @@ -1,232 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; -import 'dart:typed_data'; -import 'dart:ui' as ui; - -import 'package:file_picker/file_picker.dart'; -import 'package:flutter/material.dart'; -import 'package:inference/inference/camera_page.dart'; -import 'package:inference/canvas/canvas.dart'; -import 'package:inference/inference/device_selector.dart'; -import 'package:inference/interop/image_inference.dart'; -import 'package:inference/interop/openvino_bindings.dart'; -import 'package:inference/project.dart'; -import 'package:inference/providers/image_inference_provider.dart'; -import 'package:inference/theme.dart'; -import 'package:inference/utils/drop_area.dart'; -import 'package:provider/provider.dart'; - - -Future createImage(Uint8List bytes) async { - return await decodeImageFromList(bytes); -} - -class LiveInference extends StatefulWidget { - final Project project; - const LiveInference(this.project, {super.key}); - - @override - State createState() => _LiveInferenceState(); -} - -enum MenuButtons { camera, sample, upload } - -class _LiveInferenceState extends State { - - bool loading = false; - bool cameraMode = false; - ImageInferenceResult? inferenceResult; - ui.Image? image; - - void showUploadMenu() async { - FilePickerResult? result = await FilePicker.platform.pickFiles(type: FileType.image); - - if (result != null) { - uploadFile(result.files.single.path!); - } - } - - void uploadFile(String path) async { - Uint8List imageData = File(path).readAsBytesSync(); - setState(() { - inferenceResult = null; - loading = true; - }); - - final inferenceProvider = Provider.of(context, listen: false); - - inferenceProvider.loaded.future.then((_) async{ - final output = await inferenceProvider.infer(imageData, SerializationOutput(json: true)); - final uiImage = await decodeImageFromList(imageData); - setState(() { - loading = false; - inferenceResult = output; - image = uiImage; - }); - }); - - } - - void handleMenu(MenuButtons option) { - switch(option) { - case MenuButtons.camera: - setState(() { - cameraMode = true; - }); - break; - case MenuButtons.sample: - uploadFile(widget.project.samplePath()); - break; - case MenuButtons.upload: - showUploadMenu(); - break; - } - } - - @override - Widget build(BuildContext context) { - return Consumer( - builder: (context, inference, child) { - final isLoading = loading || inference.inference == null; - return Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const DeviceSelector(), - PopupMenuButton( - onSelected: (val) => handleMenu(val), - child: ClipRRect( - borderRadius: BorderRadius.circular(4.0), - child: Container( - decoration: BoxDecoration( - border: Border.all(color: textColor), - borderRadius: BorderRadius.circular(4.0), - color: intelGrayReallyDark, - //color: intelGrayLight, - ), - width: 168, - child: Padding( - padding: const EdgeInsets.only(top: 3, bottom: 3, left: 10, right: 5), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text("Upload image"), - const Icon( - Icons.expand_more, - color: Colors.white, - ), - ], - ), - ) - ), - ), - elevation: 0, - offset: const Offset(0, 35), - shape: RoundedRectangleBorder ( - borderRadius: BorderRadius.circular(4), - side: const BorderSide( - color: textColor, - width: 1, - ) - ), - color: intelGrayReallyDark, - itemBuilder: (BuildContext context) { - if (widget.project.hasSample) { - return >[ - const PopupMenuItem( - height: 20, - value: MenuButtons.sample, - child: MenuButton('Sample image'), - ), - const PopupMenuItem( - height: 20, - value: MenuButtons.upload, - child: MenuButton('Choose an image file'), - ), - //const PopupMenuItem( - // height: 20, - // value: MenuButtons.camera, - // child: MenuButton('Camera'), - //), - ]; - } - return >[ - const PopupMenuItem( - height: 20, - value: MenuButtons.upload, - child: MenuButton('Choose an image file'), - ), - ]; - }, - ), - ], - ), - ), - (isLoading - ? Expanded( - child: Center( - child: Image.asset('images/intel-loading.gif', width: 100) - ) - ) - : Builder( - builder: (context) { - if (cameraMode) { - return CameraPage(inference); - } - return DropArea( - type: "image", - extensions: const ["jpg, jpeg, bmp, png, tif, tiff"], - onUpload: (String path) => uploadFile(path), - showChild: inferenceResult != null, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Builder( - builder: (context) { - if (inferenceResult == null) { - return Container(); - } - return Canvas( - image: image!, - annotations: inferenceResult!.parseAnnotations(), - labelDefinitions: widget.project.labelDefinitions, - ); - } - ) - ) - ); - } - ) - ) - ], - ); - } - ); - } -} - -class MenuButton extends StatelessWidget { - final String name; - const MenuButton(this.name, { - super.key, - }); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Text(name, - style: const TextStyle( - fontSize: 10, - ), - ), - ); - - } -} - diff --git a/lib/inference/model_info.dart b/lib/inference/model_info.dart deleted file mode 100644 index 3838834f..00000000 --- a/lib/inference/model_info.dart +++ /dev/null @@ -1,114 +0,0 @@ -import 'package:collection/collection.dart'; -import 'package:flutter/material.dart'; -import 'package:inference/project.dart'; -import 'package:inference/providers/project_provider.dart'; -import 'package:inference/theme.dart'; -import 'package:provider/provider.dart'; - -class ModelInfo extends StatelessWidget { - final List children; - final Project project; - const ModelInfo(this.project, {this.children = const [], super.key}); - - // This widget is the root of your application. - @override - Widget build(BuildContext context) { - return Consumer(builder: (context, projects, child) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - PropertyItem( - name: "Model name", - child: PropertyValue(project.name) - ), - PropertyItem( - name: "Architecture", - enabled: project.tasks.firstWhereOrNull((t) => t.architecture.isNotEmpty) != null, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: project.tasks.map((task) => PropertyValue(task.architecture)).toList() - ) - ), - PropertyItem( - name: "Optimization", - enabled: project.tasks.firstWhereOrNull((t) => t.optimization.isNotEmpty) != null, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: project.tasks.map((task) => PropertyValue(task.optimization)).toList() - ) - ), - ...children - ], - ), - ); - }); - } -} - -class PropertyItem extends StatelessWidget { - final String name; - final Widget child; - final bool enabled; - const PropertyItem({required this.name, required this.child, this.enabled = true, super.key}); - - @override - Widget build(BuildContext context) { - if (!enabled) { - return Container(); - } - return Padding( - padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 8.0), - child: PropertyHeader(name), - ), - child - ] - ), - ); - } -} - -class PropertyHeader extends StatelessWidget { - final String text; - const PropertyHeader(this.text, {super.key}); - - @override - Widget build(BuildContext context) { - return Text(text, style: const TextStyle( - color: Colors.white, - fontSize: 19, - )); - } - -} - -class PropertyValue extends StatelessWidget { - final String text; - const PropertyValue(this.text, {super.key}); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.only(bottom: 8.0, right: 8.0), - child: Container( - decoration: BoxDecoration( - border: Border.all(color: textColor), - borderRadius: BorderRadius.circular(4.0), - color: intelGrayReallyDark, - ), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 6), - child: Text(text, style: const TextStyle( - fontSize: 12, - )), - ) - ), - ); - } -} diff --git a/lib/inference/text/metric_widgets.dart b/lib/inference/text/metric_widgets.dart deleted file mode 100644 index 830be84f..00000000 --- a/lib/inference/text/metric_widgets.dart +++ /dev/null @@ -1,147 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:inference/interop/openvino_bindings.dart'; -import 'package:inference/theme.dart'; -import 'package:intl/intl.dart'; - -class CirclePropRow extends StatelessWidget { - final Metrics metrics; - const CirclePropRow({super.key, required this.metrics}); - - @override - Widget build(BuildContext context) { - Locale locale = Localizations.localeOf(context); - final nf = NumberFormat.decimalPatternDigits( - locale: locale.languageCode, decimalDigits: 0); - - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - CircleProp( - header: "Time to first token (ttft)", - value: nf.format(metrics.ttft), - unit: "ms", - ), - CircleProp( - header: "Time per output token (tpot)", - value: nf.format(metrics.tpot), - unit: "ms", - ), - CircleProp( - header: "Generate total duration", - value: nf.format(metrics.generate_time), - unit: "ms", - ) - ], - ); - } -} - -class CircleProp extends StatelessWidget { - final String header; - final String value; - final String unit; - - const CircleProp({super.key, required this.header, required this.value, required this.unit}); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(16.0), - child: Container( - width: 250.0, - height: 250.0, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: intelGrayDark, - border: Border.all( - color: intelBlueDark, - width: 10, - ), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: const EdgeInsets.only(top: 36.0), - child: SizedBox( - width: 170, - child: Text(header, - style: const TextStyle( - fontSize: 20, - ), - textAlign: TextAlign.center, - ), - ), - ), - Padding( - padding: const EdgeInsets.only(bottom: 46.0), - child: Row( - textBaseline: TextBaseline.alphabetic, - crossAxisAlignment: CrossAxisAlignment.baseline, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(value, - style: const TextStyle( - fontSize: 30, - ), - ), - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: Text(unit, - style: const TextStyle( - fontSize: 12, - ), - ), - ), - ], - ), - ), - ], - ) - - ), - ); - } -} - -class Statistic extends StatelessWidget { - const Statistic({ - super.key, - required this.header, - required this.value, - required this.unit, - }); - - final String header; - final String value; - final String unit; - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(header), - Row( - textBaseline: TextBaseline.alphabetic, - crossAxisAlignment: CrossAxisAlignment.baseline, - children: [ - Text(value, - style: const TextStyle( - fontSize: 30, - ) - ), - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: Text(unit, - style: const TextStyle( - fontSize: 12, - ) - ), - ), - ], - ), - ] - ); - } -} diff --git a/lib/inference/text/performance_metrics.dart b/lib/inference/text/performance_metrics.dart deleted file mode 100644 index 6fde59e2..00000000 --- a/lib/inference/text/performance_metrics.dart +++ /dev/null @@ -1,97 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:inference/inference/text/metric_widgets.dart'; -import 'package:inference/providers/text_inference_provider.dart'; -import 'package:inference/theme.dart'; -import 'package:inference/utils/dialogs.dart'; -import 'package:intl/intl.dart'; -import 'package:provider/provider.dart'; - -class PerformanceMetricsPage extends StatefulWidget { - const PerformanceMetricsPage({super.key}); - - @override - State createState() => _PerformanceMetricsPageState(); -} - -class _PerformanceMetricsPageState extends State { - - @override - void initState() { - super.initState(); - final provider = Provider.of(context, listen: false); - if (provider.metrics == null) { - provider.loaded.future.then((_) { - provider.message("What is the purpose of OpenVINO?").catchError(onExceptionDialog(context)); - }); - } - } - - @override - Widget build(BuildContext context) { - return Consumer(builder: (context, inference, child) { - if (inference.metrics == null) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset('images/intel-loading.gif', width: 100), - const Text("Running benchmark prompt...") - ], - ) - ); - } - - Locale locale = Localizations.localeOf(context); - final nf = NumberFormat.decimalPatternDigits( - locale: locale.languageCode, decimalDigits: 0); - - final metrics = inference.metrics!; - - return Container( - decoration: BoxDecoration( - shape: BoxShape.rectangle, - borderRadius: const BorderRadius.all(Radius.circular(8)), - color: intelGray, - ), - child: Align( - alignment: Alignment.topLeft, - child: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 1000), - child: Padding( - padding: const EdgeInsets.all(30.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - CirclePropRow(metrics: metrics), - Expanded( - child: Padding( - padding: const EdgeInsets.only(top: 20.0), - child: GridView.count( - physics: const NeverScrollableScrollPhysics(), - childAspectRatio: 2.0, - padding: const EdgeInsets.only(right: 20.0), - crossAxisSpacing: 4.0, - crossAxisCount: 3, - children: [ - Statistic(header: "Tokenization duration", value: nf.format(metrics.tokenization_time), unit: "ms"), - Statistic(header: "Detokenization duration", value: nf.format(metrics.detokenization_time), unit: "ms"), - Statistic(header: "Generated tokens", value: nf.format(metrics.number_of_generated_tokens), unit: ""), - Statistic(header: "Load time", value: nf.format(metrics.load_time), unit: "ms"), - Statistic(header: "Tokens in the input prompt", value: nf.format(metrics.number_of_input_tokens), unit: ""), - Statistic(header: "Throughput", value: nf.format(metrics.throughput), unit: "tokens/sec"), - ] - ), - ), - ) - ], - ), - ), - ), - ), - ); - }); - } -} - - diff --git a/lib/inference/text/playground.dart b/lib/inference/text/playground.dart deleted file mode 100644 index 6c64dec8..00000000 --- a/lib/inference/text/playground.dart +++ /dev/null @@ -1,426 +0,0 @@ - -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:inference/config.dart'; -import 'package:inference/hint.dart'; -import 'package:inference/inference/device_selector.dart'; -import 'package:inference/inference/text/metric_widgets.dart'; -import 'package:inference/interop/openvino_bindings.dart'; -import 'package:inference/providers/text_inference_provider.dart'; -import 'package:inference/theme.dart'; -import 'package:inference/utils/dialogs.dart'; -import 'package:provider/provider.dart'; - -class Playground extends StatefulWidget { - const Playground({super.key}); - - @override - State createState() => _PlaygroundState(); -} - -class _PlaygroundState extends State { - final _controller = TextEditingController(); - final _scrollController = ScrollController(); - bool attachedToBottom = true; - - void jumpToBottom({ offset = 0 }) { - if (_scrollController.hasClients) { - _scrollController.jumpTo(_scrollController.position.maxScrollExtent + offset); - } - } - - void message(String message) async { - if (message.isEmpty) { - return; - } - final llm = provider(); - if (!llm.initialized) { - return; - } - - if (llm.response != null) { - return; - } - _controller.text = ""; - jumpToBottom(offset: 110); //move to bottom including both - llm.message(message).catchError(onExceptionDialog(context)); - } - - TextInferenceProvider provider() => Provider.of(context, listen: false); - - @override - void initState() { - super.initState(); - _scrollController.addListener(() { - setState(() { - attachedToBottom = _scrollController.position.pixels + 0.001 >= _scrollController.position.maxScrollExtent; - }); - - }); - } - - @override - void dispose() { - super.dispose(); - _controller.dispose(); - _scrollController.dispose(); - } - - - @override - Widget build(BuildContext context) { - return Consumer(builder: (context, inference, child) { - WidgetsBinding.instance.addPostFrameCallback((_) { - if (attachedToBottom) { - jumpToBottom(); - } - }); - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(left: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: const [ - DeviceSelector(), - Hint(hint: HintsEnum.intelCoreLLMPerformanceSuggestion), - ] - ), - ), - Builder( - builder: (context) { - if (!inference.initialized){ - return Expanded( - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset('images/intel-loading.gif', width: 100), - const Text("Loading model...") - ], - ) - ), - ); - } - return Expanded( - child: Container( - decoration: BoxDecoration( - shape: BoxShape.rectangle, - borderRadius: const BorderRadius.all(Radius.circular(8)), - color: intelGray, - ), - child: Column( - children: [ - Expanded( - child: Builder(builder: (context) { - if (inference.messages.isEmpty) { - return Center( - child: Text("Type a message to ${inference.project?.name ?? "assistant"}")); - } - return Stack( - alignment: Alignment.bottomCenter, - children: [ - SingleChildScrollView( - controller: _scrollController, - child: Padding( - padding: const EdgeInsets.all(20), - child: Column( - //mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: inference.messages.map((message) { - switch (message.speaker) { - case Speaker.system: - throw UnimplementedError(); - case Speaker.user: - return UserMessage(message); - case Speaker.assistant: - return AssistantMessage(message, inference.project!.name); - } - }).toList()), - ), - ), - Positioned( - bottom: 10, - child: Builder( - builder: (context) { - if (attachedToBottom) { - return Container(); - } - return Center( - child: Padding( - padding: const EdgeInsets.only(top: 2.0), - child: SizedBox( - width: 200, - height: 20, - child: FloatingActionButton( - backgroundColor: intelGray, - child: const Text("Jump to bottom"), - onPressed: () { - jumpToBottom(); - setState(() { - attachedToBottom = true; - }); - } - ), - ), - ), - ); - } - ), - ), - - ], - ); - }), - ), - - SizedBox( - height: 30, - child: Builder( - builder: (context) { - if (inference.interimResponse == null){ - return Container(); - } - return Center( - child: OutlinedButton.icon( - onPressed: () => inference.forceStop(), - icon: const Icon(Icons.stop), - label: const Text("Stop responding") - ), - ); - } - ), - ), - Padding( - padding: const EdgeInsets.only(left: 45, right: 45, top: 10, bottom: 25), - child: SizedBox( - height: 40, - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Padding( - padding: const EdgeInsets.only(right: 8), - child: IconButton( - icon: SvgPicture.asset("images/clear.svg", - colorFilter: const ColorFilter.mode(textColor, BlendMode.srcIn), - width: 20, - ), - tooltip: "Clear chat", - onPressed: () => inference.reset(), - style: IconButton.styleFrom( - backgroundColor: intelGrayReallyDark, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(4)), - side: BorderSide( - color: intelGrayLight, - width: 2, - ) - ) - ) - ), - ), - Expanded( - child: TextField( - maxLines: null, - keyboardType: TextInputType.text, - decoration: InputDecoration( - hintText: "Ask me anything...", - suffixIcon: IconButton( - icon: Icon(Icons.send, color: (inference.interimResponse == null ? Colors.white : intelGray)), - onPressed: () => message(_controller.text), - ), - enabledBorder: const OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(4)), - borderSide: BorderSide( - color: intelGrayLight, - width: 2, - ) - ), - ), - style: const TextStyle( - fontSize: 14, - ), - controller: _controller, - onSubmitted: message, - ), - ), - ], - ), - ), - ), - ], - ), - ), - ); - } - ), - ], - ); - }); - } -} - -class UserMessage extends StatelessWidget { - final Message message; - const UserMessage(this.message, {super.key}); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.only(bottom: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - NameRowWidget(name: "You", icon: SvgPicture.asset("images/user.svg", - colorFilter: const ColorFilter.mode(textColor, BlendMode.srcIn), - width: 20, - ), - ), - MessageWidget(message: message.message), - ], - ), - ); - } -} - -class AssistantMessage extends StatelessWidget { - final Message message; - final String name; - const AssistantMessage(this.message, this.name, {super.key}); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.only(bottom: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - NameRowWidget( - name: name, - icon: SvgPicture.asset("images/network.svg", - colorFilter: const ColorFilter.mode(textColor, BlendMode.srcIn), - width: 20, - ), - ), - MessageWidget(message: message.message), - Padding( - padding: const EdgeInsets.only(left: 28, top: 5), - child: Builder( - builder: (context) { - if (message.metrics == null) { - return Container(); - } - return Row( - children: [ - IconButton.filled( - icon: SvgPicture.asset("images/copy.svg", - colorFilter: const ColorFilter.mode(textColor, BlendMode.srcIn), - width: 20, - ), - style: IconButton.styleFrom( - backgroundColor: intelGrayLight, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(4)), - ), - ), - padding: const EdgeInsets.all(4), - constraints: const BoxConstraints(), - tooltip: "Copy to clipboard", - onPressed: () { - Clipboard.setData(ClipboardData(text: message.message)); - }, - ), - Padding( - padding: const EdgeInsets.only(left: 8), - child: IconButton( - style: IconButton.styleFrom( - backgroundColor: intelGrayLight, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(4)), - ), - ), - padding: const EdgeInsets.all(4), - constraints: const BoxConstraints(), - icon: SvgPicture.asset("images/stats.svg", - colorFilter: const ColorFilter.mode(textColor, BlendMode.srcIn), - width: 20, - ), - tooltip: "Show stats", - onPressed: () { - showMetricsDialog(context, message.metrics!); - }, - ), - ), - ], - ); - } - ), - ), - ], - ), - ); - } -} - -void showMetricsDialog(BuildContext context, Metrics metrics) { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - content: CirclePropRow( - metrics: metrics - ) - ); - } - ); -} - -class NameRowWidget extends StatelessWidget { - final String name; - final Widget icon; - const NameRowWidget({super.key, required this.name, required this.icon}); - - @override - Widget build(BuildContext context) { - return Row( - children: [ - Container( - padding: const EdgeInsets.all(2), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4.0), - color: intelBlueVibrant, - //color: intelGrayLight, - ), - child: icon - ), - Padding( - padding: const EdgeInsets.only(left: 10.0), - child: Text(name), - ) - ] - ); - } -} - -class MessageWidget extends StatelessWidget { - final String message; - const MessageWidget({super.key, required this.message}); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.only(left: 34.0, top: 10, right: 26), - child: SelectableText( - message, - style: const TextStyle( - color: textColor, - fontSize: 12, - ), - ), - ); - } - -} diff --git a/lib/inference/textToImage/tti_playground.dart b/lib/inference/textToImage/tti_playground.dart deleted file mode 100644 index 3a468f8c..00000000 --- a/lib/inference/textToImage/tti_playground.dart +++ /dev/null @@ -1,463 +0,0 @@ - -import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:inference/config.dart'; -import 'package:inference/hint.dart'; -import 'package:inference/inference/device_selector.dart'; -import 'package:inference/inference/textToImage/tti_metric_widgets.dart'; -import 'package:inference/interop/openvino_bindings.dart'; -import 'package:inference/providers/text_to_image_inference_provider.dart'; -import 'package:inference/theme.dart'; -import 'package:provider/provider.dart'; -import 'package:super_clipboard/super_clipboard.dart'; - -class TTIPlayground extends StatefulWidget { - const TTIPlayground({super.key}); - - @override - State createState() => _PlaygroundState(); -} - -class _PlaygroundState extends State { - final _controller = TextEditingController(); - final _scrollController = ScrollController(); - bool attachedToBottom = true; - - void jumpToBottom({ offset = 0 }) { - if (_scrollController.hasClients) { - _scrollController.jumpTo(_scrollController.position.maxScrollExtent + offset); - } - } - - void message(String message) async { - if (message.isEmpty) { - return; - } - final tti = provider(); - if (!tti.initialized) { - return; - } - - if (tti.response != null) { - return; - } - _controller.text = ""; - jumpToBottom(offset: 110); //move to bottom including both - tti.message(message); - } - - TextToImageInferenceProvider provider() => Provider.of(context, listen: false); - - @override - void initState() { - super.initState(); - _scrollController.addListener(() { - setState(() { - attachedToBottom = _scrollController.position.pixels + 0.001 >= _scrollController.position.maxScrollExtent; - }); - - }); - } - - @override - void dispose() { - super.dispose(); - _controller.dispose(); - _scrollController.dispose(); - } - - - @override - Widget build(BuildContext context) { - return Consumer(builder: (context, inference, child) { - WidgetsBinding.instance.addPostFrameCallback((_) { - if (attachedToBottom) { - jumpToBottom(); - } - }); - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Padding( - padding: EdgeInsets.only(left: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - DeviceSelector(), - Hint(hint: HintsEnum.intelCoreLLMPerformanceSuggestion), - ] - ), - ), - Builder( - builder: (context) { - if (!inference.initialized){ - return Expanded( - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset('images/intel-loading.gif', width: 100), - const Text("Loading model...") - ], - ) - ), - ); - } - return Expanded( - child: Container( - decoration: const BoxDecoration( - shape: BoxShape.rectangle, - borderRadius: BorderRadius.all(Radius.circular(8)), - color: intelGray, - ), - child: Column( - children: [ - Expanded( - child: Builder(builder: (context) { - if (inference.messages.isEmpty) { - return Center( - child: Text("Type a message to ${inference.project?.name ?? "assistant"}")); - } - return Stack( - alignment: Alignment.bottomCenter, - children: [ - SingleChildScrollView( - controller: _scrollController, - child: Padding( - padding: const EdgeInsets.all(20), - child: Column( - //mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: inference.messages.map((message) { - switch (message.speaker) { - case Speaker.user: - return UserInputMessage(message); - case Speaker.assistant: - return GeneratedImageMessage(message, inference.project!.name); - } - }).toList()), - ), - ), - Positioned( - bottom: 10, - child: Builder( - builder: (context) { - if (attachedToBottom) { - return Container(); - } - return Center( - child: Padding( - padding: const EdgeInsets.only(top: 2.0), - child: SizedBox( - width: 200, - height: 20, - child: FloatingActionButton( - backgroundColor: intelGray, - child: const Text("Jump to bottom"), - onPressed: () { - jumpToBottom(); - setState(() { - attachedToBottom = true; - }); - } - ), - ), - ), - ); - } - ), - ), - - ], - ); - }), - ), - - // SizedBox( - // height: 30, - // child: Builder( - // builder: (context) { - // if (inference.interimResponse == null){ - // return Container(); - // } - // return Center( - // child: OutlinedButton.icon( - // onPressed: () => inference.forceStop(), - // icon: const Icon(Icons.stop), - // label: const Text("Stop responding") - // ), - // ); - // } - // ), - // ), - Padding( - padding: const EdgeInsets.only(left: 45, right: 45, top: 10, bottom: 25), - child: SizedBox( - height: 40, - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Padding( - padding: const EdgeInsets.only(right: 8), - child: IconButton( - icon: SvgPicture.asset("images/clear.svg", - colorFilter: const ColorFilter.mode(textColor, BlendMode.srcIn), - width: 20, - ), - tooltip: "Clear chat", - onPressed: () => inference.reset(), - style: IconButton.styleFrom( - backgroundColor: intelGrayReallyDark, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(4)), - side: BorderSide( - color: intelGrayLight, - width: 2, - ) - ) - ) - ), - ), - Expanded( - child: TextField( - maxLines: null, - keyboardType: TextInputType.text, - decoration: InputDecoration( - hintText: "Ask me anything...", - suffixIcon: IconButton( - icon: Icon(Icons.send, color: (inference.interimResponse == null ? Colors.white : intelGray)), - onPressed: () => message(_controller.text), - ), - enabledBorder: const OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(4)), - borderSide: BorderSide( - color: intelGrayLight, - width: 2, - ) - ), - ), - style: const TextStyle( - fontSize: 14, - ), - controller: _controller, - onSubmitted: message, - ), - ), - ], - ), - ), - ), - ], - ), - ), - ); - } - ), - ], - ); - }); - } -} - -class UserInputMessage extends StatelessWidget { - final Message message; - const UserInputMessage(this.message, {super.key}); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.only(bottom: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - NameRowWidget(name: "You", icon: SvgPicture.asset("images/user.svg", - colorFilter: const ColorFilter.mode(textColor, BlendMode.srcIn), - width: 20, - ), - ), - MessageWidget(message: message.message), - ], - ), - ); - } -} - -class GeneratedImageMessage extends StatelessWidget { - final Message message; - final String name; - const GeneratedImageMessage(this.message, this.name, {super.key}); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.only(bottom: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - NameRowWidget( - name: name, - icon: SvgPicture.asset("images/network.svg", - colorFilter: const ColorFilter.mode(textColor, BlendMode.srcIn), - width: 20, - ), - ), - ImageWidget(message: message.message, image: Image.memory(message.imageContent!.imageData, width: message.imageContent!.width.toDouble(), height: message.imageContent!.height.toDouble(), fit: message.imageContent!.boxFit)), - Padding( - padding: const EdgeInsets.only(left: 28, top: 5), - child: Builder( - builder: (context) { - if (message.speaker == Speaker.user) { - return Container(); - } - return Row( - children: [ - Opacity( - opacity: message.allowedCopy ? 1.0 : 0.25, - child: - IconButton.filled( - icon: SvgPicture.asset("images/copy.svg", - colorFilter: const ColorFilter.mode(textColor, BlendMode.srcIn), - width: 20, - ), - style: IconButton.styleFrom( - backgroundColor: intelGrayLight, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(4)), - ), - ), - padding: const EdgeInsets.all(4), - constraints: const BoxConstraints(), - tooltip: message.allowedCopy ? "Copy to clipboard" : null, - onPressed: message.imageContent?.imageData == null || message.allowedCopy == false ? null : () { - - final clipboard = SystemClipboard.instance; - if (clipboard == null) { - return; // Clipboard API is not supported on this platform. - } - final item = DataWriterItem(); - item.add(Formats.jpeg(message.imageContent!.imageData)); - clipboard.write([item]); - - }, - ) - ), - Padding( - padding: const EdgeInsets.only(left: 8), - child: IconButton( - style: IconButton.styleFrom( - backgroundColor: intelGrayLight, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(4)), - ), - ), - padding: const EdgeInsets.all(4), - constraints: const BoxConstraints(), - icon: SvgPicture.asset("images/stats.svg", - colorFilter: const ColorFilter.mode(textColor, BlendMode.srcIn), - width: 20, - ), - tooltip: "Show stats", - onPressed: () { - showMetricsDialog(context, message.metrics!); - }, - ), - ), - ], - ); - } - ), - ), - ], - ), - ); - } -} - -void showMetricsDialog(BuildContext context, TTIMetrics metrics) { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - content: TTICirclePropRow( - metrics: metrics - ) - ); - } - ); -} - -class NameRowWidget extends StatelessWidget { - final String name; - final Widget icon; - const NameRowWidget({super.key, required this.name, required this.icon}); - - @override - Widget build(BuildContext context) { - return Row( - children: [ - Container( - padding: const EdgeInsets.all(2), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4.0), - color: intelBlueVibrant, - //color: intelGrayLight, - ), - child: icon - ), - Padding( - padding: const EdgeInsets.only(left: 10.0), - child: Text(name), - ) - ] - ); - } -} - -class MessageWidget extends StatelessWidget { - final String message; - const MessageWidget({super.key, required this.message}); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.only(left: 34.0, top: 10, right: 26), - child: SelectableText( - message, - style: const TextStyle( - color: textColor, - fontSize: 12, - ), - ), - ); - } - -} - -class ImageWidget extends StatelessWidget { - final String message; - final Image? image; - const ImageWidget({super.key, required this.message, required this.image}); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.only(left: 34.0, top: 10, right: 26), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Image widget goes here - image ?? Container(), - const SizedBox(height: 8), // Add some spacing between image and text - SelectableText( - message, - style: const TextStyle( - color: textColor, - fontSize: 12, - ), - ), - ], - ), - ); - } -} diff --git a/lib/inference/text_inference_page.dart b/lib/inference/text_inference_page.dart deleted file mode 100644 index afe0e5cd..00000000 --- a/lib/inference/text_inference_page.dart +++ /dev/null @@ -1,165 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:inference/header.dart'; -import 'package:inference/inference/model_info.dart'; -import 'package:inference/inference/text/performance_metrics.dart'; -import 'package:inference/inference/text/playground.dart'; -import 'package:inference/project.dart'; -import 'package:inference/providers/preference_provider.dart'; -import 'package:inference/providers/text_inference_provider.dart'; -import 'package:inference/theme.dart'; -import 'package:inference/utils/dialogs.dart'; -import 'package:intl/intl.dart'; -import 'package:provider/provider.dart'; - -class TextInferencePage extends StatefulWidget { - final Project project; - const TextInferencePage(this.project, {super.key}); - - @override - State createState() => _TextInferencePageState(); -} - -class _TextInferencePageState extends State with TickerProviderStateMixin { - - late TabController _tabController; - - @override - void initState() { - super.initState(); - _tabController = TabController(length: 2, animationDuration: Duration.zero, vsync: this); - } - - @override - void dispose() { - _tabController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - Locale locale = Localizations.localeOf(context); - - return ChangeNotifierProxyProvider( - create: (_) { - return TextInferenceProvider(widget.project, null); - }, - update: (_, preferences, textInferenceProvider) { - final init = textInferenceProvider == null || - !textInferenceProvider.sameProps(widget.project, preferences.device); - if (init) { - final textInferenceProvider = TextInferenceProvider(widget.project, preferences.device); - textInferenceProvider.loadModel().catchError(onExceptionDialog(context)); - return textInferenceProvider; - } - if (!textInferenceProvider.sameProps(widget.project, preferences.device)) { - return TextInferenceProvider(widget.project, preferences.device); - } - return textInferenceProvider; - }, - child: Scaffold( - appBar: const Header(true), - body: Padding( - padding: const EdgeInsets.only(left: 58, right: 58, bottom: 30), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Consumer( - builder: (context, inference, child) { - final nf = NumberFormat.decimalPatternDigits( - locale: locale.languageCode, decimalDigits: 2); - - return SizedBox( - width: 250, - child: ModelInfo( - widget.project, - children: [ - PropertyItem( - name: "Task", - child: PropertyValue(inference.task), - ), - Padding( - padding: const EdgeInsets.only(left: 12, top: 12, right: 20.0), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text("Temperature"), - Text(nf.format(inference.temperature)) - ] - ), - Slider( - value: inference.temperature, - max: 2.0, - onChanged: (double value) { - inference.temperature = value; - }, - - ), - ], - ), - ), - Padding( - padding: const EdgeInsets.only(left: 12, top: 12, right: 20.0), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text("Top P"), - Text(nf.format(inference.topP)) - ] - ), - Slider( - value: inference.topP, - max: 1.0, - onChanged: (double value) { - inference.topP = value; - }, - - ), - ], - ), - ), - ] - ), - ); - }), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - TabBar( - isScrollable: true, - tabAlignment: TabAlignment.start, - controller: _tabController, - tabs: const [ - Tab(text: "Playground"), - Tab(text: "Performance metrics"), - //Tab(text: "Deploy"), - ] - ), - Expanded( - child: Padding( - padding: const EdgeInsets.only(top: 15.0), - child: TabBarView( - controller: _tabController, - children: [ - const Playground(), - const PerformanceMetricsPage(), - //Container(), - ] - ), - ) - ), - ], - ), - ) - ], - ), - ), - ), - ); - } -} - diff --git a/lib/inference/text_to_image_inference_page.dart b/lib/inference/text_to_image_inference_page.dart deleted file mode 100644 index 509725db..00000000 --- a/lib/inference/text_to_image_inference_page.dart +++ /dev/null @@ -1,187 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:inference/header.dart'; -import 'package:inference/inference/model_info.dart'; -import 'package:inference/inference/textToImage/tti_performance_metrics.dart'; -import 'package:inference/inference/textToImage/tti_playground.dart'; -import 'package:inference/project.dart'; -import 'package:inference/providers/preference_provider.dart'; -import 'package:inference/providers/text_to_image_inference_provider.dart'; -import 'package:intl/intl.dart'; -import 'package:provider/provider.dart'; - -class TextToImageInferencePage extends StatefulWidget { - final Project project; - const TextToImageInferencePage(this.project, {super.key}); - - @override - State createState() => _TextToImageInferencePageState(); -} - -class _TextToImageInferencePageState extends State with TickerProviderStateMixin { - - late TabController _tabController; - - @override - void initState() { - super.initState(); - _tabController = TabController(length: 2, animationDuration: Duration.zero, vsync: this); - } - - @override - void dispose() { - _tabController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - Locale locale = Localizations.localeOf(context); - - return ChangeNotifierProxyProvider( - create: (_) { - return TextToImageInferenceProvider(widget.project, null); - }, - update: (_, preferences, textToImageInferenceProvider) { - if (textToImageInferenceProvider == null) { - return TextToImageInferenceProvider(widget.project, preferences.device); - } - if (!textToImageInferenceProvider.sameProps(widget.project, preferences.device)) { - return TextToImageInferenceProvider(widget.project, preferences.device); - } - return textToImageInferenceProvider; - }, - child: Scaffold( - appBar: const Header(true), - body: Padding( - padding: const EdgeInsets.only(left: 58, right: 58, bottom: 30), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Consumer( - builder: (context, inference, child) { - final nf = NumberFormat.decimalPatternDigits( - locale: locale.languageCode, decimalDigits: 2); - - return SizedBox( - width: 250, - child: ModelInfo( - widget.project, - children: [ - PropertyItem( - name: "Task", - child: PropertyValue(inference.task), - ), - Padding( - padding: const EdgeInsets.only(left: 12, top: 12, right: 20.0), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text("Width"), - Text(nf.format(inference.width)) - ] - ), - Slider( - value: inference.width.toDouble(), - max: 1024.0, - min: 64, - divisions: (1024-64)~/64, - onChanged: (double value) { - inference.width = value.toInt(); - }, - - ), - ], - ), - ), - Padding( - padding: const EdgeInsets.only(left: 12, top: 12, right: 20.0), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text("Height"), - Text(nf.format(inference.height)) - ] - ), - Slider( - value: inference.height.toDouble(), - max: 1024.0, - min: 64, - divisions: (1024-64)~/64, - onChanged: (double value) { - inference.height = value.toInt(); - }, - - ), - ], - ), - ), - Padding( - padding: const EdgeInsets.only(left: 12, top: 12, right: 20.0), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text("Rounds"), - Text(nf.format(inference.rounds)) - ] - ), - Slider( - value: inference.rounds.toDouble(), - max: 80, - min: 1, - divisions: (80-1)~/1, - onChanged: (double value) { - inference.rounds = value.toInt(); - }, - - ), - ], - ), - ), - ] - ), - ); - }), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - TabBar( - isScrollable: true, - tabAlignment: TabAlignment.start, - controller: _tabController, - tabs: const [ - Tab(text: "Playground"), - Tab(text: "Performance metrics"), - //Tab(text: "Deploy"), - ] - ), - Expanded( - child: Padding( - padding: const EdgeInsets.only(top: 15.0), - child: TabBarView( - controller: _tabController, - children: const [ - TTIPlayground(), - TTIPerformanceMetricsPage(), - //Container(), - ] - ), - ) - ), - ], - ), - ) - ], - ), - ), - ), - ); - } -} - diff --git a/lib/interop/generated_bindings.dart b/lib/interop/generated_bindings.dart index 4d824acc..08f9547d 100644 --- a/lib/interop/generated_bindings.dart +++ b/lib/interop/generated_bindings.dart @@ -92,6 +92,37 @@ class OpenVINO { late final _freeStatusOrSpeechToText = _freeStatusOrSpeechToTextPtr .asFunction)>(); + void freeStatusOrModelResponse( + ffi.Pointer status, + ) { + return _freeStatusOrModelResponse( + status, + ); + } + + late final _freeStatusOrModelResponsePtr = _lookup< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer)>>( + 'freeStatusOrModelResponse'); + late final _freeStatusOrModelResponse = _freeStatusOrModelResponsePtr + .asFunction)>(); + + void freeStatusOrWhisperModelResponse( + ffi.Pointer status, + ) { + return _freeStatusOrWhisperModelResponse( + status, + ); + } + + late final _freeStatusOrWhisperModelResponsePtr = _lookup< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer)>>( + 'freeStatusOrWhisperModelResponse'); + late final _freeStatusOrWhisperModelResponse = + _freeStatusOrWhisperModelResponsePtr.asFunction< + void Function(ffi.Pointer)>(); + void freeStatusOrDevices( ffi.Pointer status, ) { @@ -644,6 +675,80 @@ class OpenVINO { late final _graphRunnerStop = _graphRunnerStopPtr .asFunction Function(CGraphRunner)>(); + ffi.Pointer speechToTextOpen( + ffi.Pointer model_path, + ffi.Pointer device, + ) { + return _speechToTextOpen( + model_path, + device, + ); + } + + late final _speechToTextOpenPtr = _lookup< + ffi.NativeFunction< + ffi.Pointer Function(ffi.Pointer, + ffi.Pointer)>>('speechToTextOpen'); + late final _speechToTextOpen = _speechToTextOpenPtr.asFunction< + ffi.Pointer Function( + ffi.Pointer, ffi.Pointer)>(); + + ffi.Pointer speechToTextLoadVideo( + CSpeechToText instance, + ffi.Pointer video_path, + ) { + return _speechToTextLoadVideo( + instance, + video_path, + ); + } + + late final _speechToTextLoadVideoPtr = _lookup< + ffi.NativeFunction< + ffi.Pointer Function(CSpeechToText, + ffi.Pointer)>>('speechToTextLoadVideo'); + late final _speechToTextLoadVideo = _speechToTextLoadVideoPtr.asFunction< + ffi.Pointer Function(CSpeechToText, ffi.Pointer)>(); + + ffi.Pointer speechToTextVideoDuration( + CSpeechToText instance, + ) { + return _speechToTextVideoDuration( + instance, + ); + } + + late final _speechToTextVideoDurationPtr = _lookup< + ffi.NativeFunction Function(CSpeechToText)>>( + 'speechToTextVideoDuration'); + late final _speechToTextVideoDuration = _speechToTextVideoDurationPtr + .asFunction Function(CSpeechToText)>(); + + ffi.Pointer speechToTextTranscribe( + CSpeechToText instance, + int start, + int duration, + ffi.Pointer language, + ) { + return _speechToTextTranscribe( + instance, + start, + duration, + language, + ); + } + + late final _speechToTextTranscribePtr = _lookup< + ffi.NativeFunction< + ffi.Pointer Function( + CSpeechToText, + ffi.Int, + ffi.Int, + ffi.Pointer)>>('speechToTextTranscribe'); + late final _speechToTextTranscribe = _speechToTextTranscribePtr.asFunction< + ffi.Pointer Function( + CSpeechToText, int, int, ffi.Pointer)>(); + ffi.Pointer getAvailableDevices() { return _getAvailableDevices(); } @@ -762,6 +867,16 @@ final class Device extends ffi.Struct { external ffi.Pointer name; } +final class TranscriptionChunk extends ffi.Struct { + @ffi.Float() + external double start_ts; + + @ffi.Float() + external double end_ts; + + external ffi.Pointer text; +} + final class Status extends ffi.Struct { @ffi.Int() external int status; @@ -862,6 +977,22 @@ final class StatusOrModelResponse extends ffi.Struct { external ffi.Pointer value; } +final class StatusOrWhisperModelResponse extends ffi.Struct { + @ffi.Int() + external int status; + + external ffi.Pointer message; + + external Metrics metrics; + + external ffi.Pointer value; + + @ffi.Int() + external int size; + + external ffi.Pointer text; +} + final class StatusOrTTIModelResponse extends ffi.Struct { @ffi.Int() external int status; diff --git a/lib/interop/openvino_bindings.dart b/lib/interop/openvino_bindings.dart index fd3ffb03..d27cd8b7 100644 --- a/lib/interop/openvino_bindings.dart +++ b/lib/interop/openvino_bindings.dart @@ -18,6 +18,20 @@ class SerializationOutput { } +class Chunk { + final double start; + final double end; + final String text; + const Chunk(this.start, this.end, this.text); +} + +class TranscriptionModelResponse { + final List chunks; + final Metrics metrics; + final String text; + const TranscriptionModelResponse(this.chunks, this.metrics, this.text); +} + class ModelResponse { final String content; final Metrics metrics; diff --git a/lib/interop/speech_to_text.dart b/lib/interop/speech_to_text.dart index c8635ae1..4f57cb2d 100644 --- a/lib/interop/speech_to_text.dart +++ b/lib/interop/speech_to_text.dart @@ -9,72 +9,79 @@ final ov = getBindings(); class SpeechToText { final Pointer instance; - - SpeechToText(this.instance); static Future init(String modelPath, String device) async { - throw UnimplementedError(); - //final result = await Isolate.run(() { - // final modelPathPtr = modelPath.toNativeUtf8(); - // final devicePtr = device.toNativeUtf8(); - // final status = ov.speechToTextOpen(modelPathPtr, devicePtr); - // calloc.free(modelPathPtr); - // calloc.free(devicePtr); - - // return status; - //}); - - //print("${result.ref.status}, ${result.ref.message}"); - //if (StatusEnum.fromValue(result.ref.status) != StatusEnum.OkStatus) { - // throw "SpeechToText open error: ${result.ref.status} ${result.ref.message.toDartString()}"; - //} - - //return SpeechToText(result); + final result = await Isolate.run(() { + final modelPathPtr = modelPath.toNativeUtf8(); + final devicePtr = device.toNativeUtf8(); + final status = ov.speechToTextOpen(modelPathPtr, devicePtr); + calloc.free(modelPathPtr); + calloc.free(devicePtr); + + return status; + }); + + print("${result.ref.status}, ${result.ref.message}"); + if (StatusEnum.fromValue(result.ref.status) != StatusEnum.OkStatus) { + throw "SpeechToText open error: ${result.ref.status} ${result.ref.message.toDartString()}"; + } + + return SpeechToText(result); } Future loadVideo(String videoPath) async{ - throw UnimplementedError(); - //int instanceAddress = instance.ref.value.address; - //{ - // final result = await Isolate.run(() { - // final videoPathPtr = videoPath.toNativeUtf8(); - // final status = ov.speechToTextLoadVideo(Pointer.fromAddress(instanceAddress), videoPathPtr); - // calloc.free(videoPathPtr); - // return status; - // }); - - // if (StatusEnum.fromValue(result.ref.status) != StatusEnum.OkStatus) { - // throw "SpeechToText LoadVideo error: ${result.ref.status} ${result.ref.message.toDartString()}"; - // } - //} - - //{ - // final result = await Isolate.run(() { - // final status = ov.speechToTextVideoDuration(Pointer.fromAddress(instanceAddress)); - // return status; - // }); - // if (StatusEnum.fromValue(result.ref.status) != StatusEnum.OkStatus) { - // throw "SpeechToText VideoDuration error: ${result.ref.status} ${result.ref.message.toDartString()}"; - // } - // return result.ref.value; - //} + int instanceAddress = instance.ref.value.address; + { + final result = await Isolate.run(() { + final videoPathPtr = videoPath.toNativeUtf8(); + final status = ov.speechToTextLoadVideo(Pointer.fromAddress(instanceAddress), videoPathPtr); + calloc.free(videoPathPtr); + return status; + }); + + if (StatusEnum.fromValue(result.ref.status) != StatusEnum.OkStatus) { + throw "SpeechToText LoadVideo error: ${result.ref.status} ${result.ref.message.toDartString()}"; + } + } + + { + final result = await Isolate.run(() { + final status = ov.speechToTextVideoDuration(Pointer.fromAddress(instanceAddress)); + return status; + }); + if (StatusEnum.fromValue(result.ref.status) != StatusEnum.OkStatus) { + throw "SpeechToText VideoDuration error: ${result.ref.status} ${result.ref.message.toDartString()}"; + } + return result.ref.value; + } } - Future transcribe(int start, int duration, String language) async{ - throw UnimplementedError(); - //int instanceAddress = instance.ref.value.address; - //final result = await Isolate.run(() { - // final languagePtr = language.toNativeUtf8(); - // final status = ov.speechToTextTranscribe(Pointer.fromAddress(instanceAddress), start, duration, languagePtr); - // calloc.free(languagePtr); - // return status; - //}); - - //if (StatusEnum.fromValue(result.ref.status) != StatusEnum.OkStatus) { - // throw "SpeechToText LoadVideo error: ${result.ref.status} ${result.ref.message.toDartString()}"; - //} - - //return result.ref.value.toDartString(); + Future transcribe(int start, int duration, String language) async{ + int instanceAddress = instance.ref.value.address; + final result = await Isolate.run(() { + final languagePtr = language.toNativeUtf8(); + final status = ov.speechToTextTranscribe(Pointer.fromAddress(instanceAddress), start, duration, languagePtr); + calloc.free(languagePtr); + return status; + }); + + if (StatusEnum.fromValue(result.ref.status) != StatusEnum.OkStatus) { + throw "SpeechToText LoadVideo error: ${result.ref.status} ${result.ref.message.toDartString()}"; + } + + List chunks = []; + for (int i = 0; i < result.ref.size; i++) { + chunks.add(Chunk( + result.ref.value[i].start_ts, + result.ref.value[i].end_ts, + result.ref.value[i].text.toDartString() + )); + } + final metrics = result.ref.metrics; + final text = result.ref.text.toDartString(); + ov.freeStatusOrWhisperModelResponse(result); + + return TranscriptionModelResponse(chunks, metrics, text); } } diff --git a/lib/main.dart b/lib/main.dart index 3c5b79b6..092cccd4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,15 +1,20 @@ import 'package:dio/dio.dart'; -import 'package:flutter/material.dart'; +import 'package:fluent_ui/fluent_ui.dart'; import 'package:inference/config.dart'; -import 'package:inference/openvino_console_app.dart'; +import 'package:inference/router.dart'; +import 'package:inference/theme_fluent.dart'; import 'package:inference/providers/preference_provider.dart'; import 'package:inference/providers/project_provider.dart'; import 'package:inference/public_models.dart'; +import 'package:media_kit/media_kit.dart'; import 'package:provider/provider.dart'; + +const String title = 'OpenVINO TestDrive'; + void testConnection() async { final dio = Dio(BaseOptions(connectTimeout: Duration(seconds: 10))); - + try { await dio.get(collections[0].path); } on DioException catch(ex) { @@ -21,6 +26,7 @@ void testConnection() async { } void main() { + MediaKit.ensureInitialized(); testConnection(); runApp(const App()); } @@ -34,8 +40,42 @@ class App extends StatelessWidget { providers: [ ChangeNotifierProvider(create: (_) => PreferenceProvider(PreferenceProvider.defaultDevice)), ChangeNotifierProvider(create: (_) => ProjectProvider([])), + ChangeNotifierProvider(create: (_) => AppTheme()), ], - child: const OpenVINOTestDriveApp(), + builder: (context, child) { + final theme = context.watch(); + return FluentApp.router( + title: title, + themeMode: theme.mode, + debugShowCheckedModeBanner: false, + color: theme.color, + theme: FluentThemeData( + accentColor: theme.color, + scaffoldBackgroundColor: const Color(0x80FFFFFF), + visualDensity: VisualDensity.standard, + fontFamily: theme.fontFamily, + ), + darkTheme: FluentThemeData( + brightness: Brightness.dark, + scaffoldBackgroundColor: const Color(0xFF2C2C2C), + accentColor: theme.darkColor, + cardColor: const Color(0xFF383838), + visualDensity: VisualDensity.standard, + fontFamily: theme.fontFamily, + ), + // locale: theme.locale, + builder: (context, child) => NavigationPaneTheme( + data: const NavigationPaneThemeData( + // backgroundColor: theme.windowEffect != flutter_acrylic.WindowEffect.disabled + // ? Colors.transparent : null, + ), + child: child!, + ), + routeInformationParser: router.routeInformationParser, + routerDelegate: router.routerDelegate, + routeInformationProvider: router.routeInformationProvider, + ); + }, ); } } diff --git a/lib/openvino_console_app.dart b/lib/openvino_console_app.dart index 7e08a273..8b3b97fe 100644 --- a/lib/openvino_console_app.dart +++ b/lib/openvino_console_app.dart @@ -1,40 +1,25 @@ import 'package:go_router/go_router.dart'; -import 'package:flutter/material.dart'; import 'package:inference/deployment_processor.dart'; -import 'package:inference/import/import_page.dart'; -import 'package:inference/inference/inference_page.dart'; import 'package:inference/interop/device.dart'; import 'package:inference/interop/image_inference.dart'; -import 'package:inference/project.dart'; -import 'package:inference/projects/projects_page.dart'; import 'package:inference/providers/preference_provider.dart'; import 'package:inference/providers/project_provider.dart'; -import 'package:inference/theme.dart'; +import 'package:inference/theme_fluent.dart'; import 'package:inference/utils.dart'; import 'package:provider/provider.dart'; - -final GoRouter _router = GoRouter( - routes: [ - GoRoute( - path: '/', - pageBuilder: (context, state) => const NoTransitionPage(child: ProjectsPage()), - routes: [ - GoRoute( - path: 'inference', - pageBuilder: (context, state) => NoTransitionPage(child: InferencePage(state.extra! as Project)), - ), - GoRoute( - path: 'import', - pageBuilder: (context, state) => const NoTransitionPage(child: ImportPage()), - ), - ], - ), - ], -); +import 'package:fluent_ui/fluent_ui.dart'; class OpenVINOTestDriveApp extends StatefulWidget { - const OpenVINOTestDriveApp({super.key}); + const OpenVINOTestDriveApp({ + super.key, + required this.child, + required this.shellContext, + }); + + + final Widget child; + final BuildContext? shellContext; @override State createState() => _OpenVINOTestDriveAppState(); @@ -43,6 +28,7 @@ class OpenVINOTestDriveApp extends StatefulWidget { class _OpenVINOTestDriveAppState extends State { @override void initState() { + //NOTE: Do we need to add listeneres to windowManager here? super.initState(); //setLoggingOutput(); @@ -53,7 +39,6 @@ class _OpenVINOTestDriveAppState extends State { setupErrors(); Device.getDevices().then((devices) { - devices.forEach((p) => print("${p.id}, ${p.name}")); PreferenceProvider.availableDevices = devices; }); @@ -62,11 +47,103 @@ class _OpenVINOTestDriveAppState extends State { loadProjectsFromStorage().then(addProjects); } + late final List originalNavigationItems = [ + PaneItem( + key: const ValueKey('/home'), + icon: const Icon(FluentIcons.home), + title: const Text('Home'), + body: const SizedBox.shrink() + ), + PaneItem( + key: const ValueKey('/models'), + icon: const Icon(FluentIcons.iot), + title: const Text('Models'), + body: const SizedBox.shrink() + ), + PaneItem( + key: const ValueKey('/workflows'), + icon: const Icon(FluentIcons.flow), + title: const Text('Workflows'), + body: const SizedBox.shrink(), + enabled: false, + ), + PaneItem( + key: const ValueKey('/rag'), + icon: const Icon(FluentIcons.library), + title: const Text('Knowledge base'), + body: const SizedBox.shrink(), + enabled: false + ) + ].map((item) => PaneItem( + key: item.key, + icon: item.icon, + title: item.title, + body: item.body, + enabled: item.enabled, + onTap: () { + final path = (item.key as ValueKey).value; + if (GoRouterState.of(context).uri.toString() != path) { + GoRouter.of(context).go(path); + } + item.onTap?.call(); + }, + )).toList(); + + late final List footerNavigationItems = [ + PaneItem( + title: const Text('Dark mode'), + icon: Builder(builder: (context) { + final appTheme = context.watch(); + if (appTheme.mode == ThemeMode.dark) { + return const Icon(FluentIcons.clear_night); + } else if (appTheme.mode == ThemeMode.light) { + return const Icon(FluentIcons.brightness); + } else { + return const Icon(FluentIcons.half_alpha); + } + }), + body: const SizedBox.shrink(), + onTap: () { + final appTheme = context.read(); + appTheme.toggleTheme(); + }, + ), + ]; + + int? _calculateSelectedIndex(BuildContext context) { + final uri = GoRouterState.of(context).uri.toString(); + int? index = originalNavigationItems + .indexWhere((item) { + return uri.startsWith((item.key as ValueKey).value); + }); + if (index == -1) { + index = null; + } + return index; + } + @override Widget build(BuildContext context) { - return MaterialApp.router( - theme: intelTheme, - routerConfig: _router, - ); + return NavigationView( + appBar: NavigationAppBar( + leading: Container(), + height: 48, + ), + paneBodyBuilder: (item, child) { + final name = + item?.key is ValueKey ? (item!.key as ValueKey).value : null; + return FocusTraversalGroup( + key: ValueKey('body$name'), + child: widget.child, + ); + }, + pane: NavigationPane( + selected: _calculateSelectedIndex(context), + toggleable: false, + displayMode: PaneDisplayMode.compact, + items: originalNavigationItems, + footerItems: footerNavigationItems, + ), + ); } } diff --git a/lib/pages/computer_vision/batch_inference.dart b/lib/pages/computer_vision/batch_inference.dart new file mode 100644 index 00000000..53c74ff5 --- /dev/null +++ b/lib/pages/computer_vision/batch_inference.dart @@ -0,0 +1,109 @@ + import 'package:fluent_ui/fluent_ui.dart'; +import 'package:inference/interop/openvino_bindings.dart'; +import 'package:inference/pages/computer_vision/providers/batch_inference_provider.dart'; +import 'package:inference/pages/computer_vision/widgets/folder_selector.dart'; +import 'package:inference/pages/computer_vision/widgets/horizontal_rule.dart'; +import 'package:inference/pages/computer_vision/widgets/model_properties.dart'; +import 'package:inference/pages/computer_vision/widgets/output_selector.dart'; +import 'package:inference/pages/computer_vision/widgets/device_selector.dart'; +import 'package:inference/providers/image_inference_provider.dart'; +import 'package:provider/provider.dart'; + +class BatchInference extends StatelessWidget { + const BatchInference({super.key}); + + @override + Widget build(BuildContext context) { + return ChangeNotifierProxyProvider( + lazy: false, + update: (_, imageInference, batchInferenceProvider) { + if (batchInferenceProvider != null) { + if (batchInferenceProvider.imageInference != imageInference) { + batchInferenceProvider.imageInference = imageInference; + } + return batchInferenceProvider; + } + return BatchInferenceProvider(imageInference, SerializationOutput(overlay: true)); + }, + create: (BuildContext context) { + return BatchInferenceProvider(context.read(), SerializationOutput(overlay: true)); + }, + child: Consumer(builder: (context, batchInference, child) { + return Row( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 64, vertical: 24), + child: Align( + alignment: Alignment.topLeft, + child: ConstrainedBox( + constraints: const BoxConstraints( + maxWidth: 720, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + FolderSelector( + label: "Source folder", + onSubmit: (v) => batchInference.sourceFolder = v, + ), + const HorizontalRule(), + FolderSelector( + label: "Destination folder", + onSubmit: (v) => batchInference.destinationFolder = v, + ), + const HorizontalRule(), + const OutputSelector(), + const HorizontalRule(), + const DeviceSelector(), + const HorizontalRule(), + Row( + children: [ + FilledButton( + onPressed: () { + if (batchInference.state == BatchInferenceState.Running) { + batchInference.stop(); + } else { + batchInference.start(); + } + + }, + child: Builder( + builder: (context) { + String text = switch(batchInference.state) { + BatchInferenceState.Ready => "Start batch inference", + BatchInferenceState.Running => "Stop", + BatchInferenceState.Done => "Start batch inference", + }; + return Text(text); + } + ), + ), + Builder( + builder: (context) { + if (batchInference.progress == null) { + return Container(); + } + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: ProgressBar(value: batchInference.progress!.percentage() * 100), + ); + } + ), + ], + ), + ], + ), + ), + ), + ), + ), + ModelProperties(project: batchInference.imageInference.project), + ], + ); + } + ), + ); + } +} diff --git a/lib/pages/computer_vision/computer_vision.dart b/lib/pages/computer_vision/computer_vision.dart new file mode 100644 index 00000000..715a270e --- /dev/null +++ b/lib/pages/computer_vision/computer_vision.dart @@ -0,0 +1,136 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:go_router/go_router.dart'; +import 'package:inference/pages/computer_vision/batch_inference.dart'; +import 'package:inference/pages/computer_vision/live_inference.dart'; +import 'package:inference/project.dart'; +import 'package:inference/providers/image_inference_provider.dart'; +import 'package:inference/providers/preference_provider.dart'; +import 'package:provider/provider.dart'; + +class ComputerVisionPage extends StatefulWidget { + final Project project; + const ComputerVisionPage(this.project, {super.key}); + + @override + State createState() => _ComputerVisionPageState(); +} + +class _ComputerVisionPageState extends State { + + + int selected = 0; + @override + Widget build(BuildContext context) { + final theme = FluentTheme.of(context); + final updatedTheme = theme.copyWith( + navigationPaneTheme: theme.navigationPaneTheme.merge(NavigationPaneThemeData( + backgroundColor: theme.scaffoldBackgroundColor, + )) + ); + + return ChangeNotifierProxyProvider( + lazy: false, + create: (_) { + final device = Provider.of(context, listen: false).device; + return ImageInferenceProvider(widget.project, device)..init(); + }, + update: (_, preferences, imageInferenceProvider) { + if (imageInferenceProvider != null && imageInferenceProvider.sameProps(widget.project, preferences.device)) { + return imageInferenceProvider; + } + return ImageInferenceProvider(widget.project, preferences.device)..init(); + }, + child: Stack( + children: [ + FluentTheme( + data: updatedTheme, + child: NavigationView( + pane: NavigationPane( + size: const NavigationPaneSize(topHeight: 64), + header: Row( + children: [ + Padding( + padding: const EdgeInsets.only(left: 12.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(4.0), + child: Container( + width: 40, + height: 40, + decoration: BoxDecoration( + image: DecorationImage( + image: widget.project.thumbnailImage(), + fit: BoxFit.cover), + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text(widget.project.name, + style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + ), + ], + ), + //customPane: CustomNavigationPane(), + selected: selected, + onChanged: (i) => setState(() {selected = i;}), + displayMode: PaneDisplayMode.top, + items: [ + PaneItem( + icon: const Icon(FluentIcons.processing), + title: const Text("Live Inference"), + body: LiveInference(project: widget.project), + ), + PaneItem( + icon: const Icon(FluentIcons.project_collection), + title: const Text("Batch Inference"), + body: const BatchInference(), + ), + ], + ) + ), + ), + SizedBox( + height: 64, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 25), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + //Padding( + // padding: const EdgeInsets.all(4), + // child: FilledButton( + // child: const Text("Download"), + // onPressed: () => print("close") + // ), + //), + //Padding( + // padding: const EdgeInsets.all(4), + // child: OutlinedButton( + // child: const Text("Fine-tune"), + // onPressed: () => print("close") + // ), + //), + Padding( + padding: const EdgeInsets.all(4), + child: OutlinedButton( + style: ButtonStyle( + shape:WidgetStatePropertyAll(RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4.0), + side: const BorderSide(color: Color(0XFF545454)), + )), + ), + child: const Text("Close"), + onPressed: () => GoRouter.of(context).go("/models"), + ), + ), + ] + ), + ), + ) + ], + ), + ); + } +} diff --git a/lib/pages/computer_vision/live_inference.dart b/lib/pages/computer_vision/live_inference.dart new file mode 100644 index 00000000..c779c4dd --- /dev/null +++ b/lib/pages/computer_vision/live_inference.dart @@ -0,0 +1,142 @@ +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:file_picker/file_picker.dart'; +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:inference/interop/image_inference.dart'; +import 'package:inference/interop/openvino_bindings.dart'; +import 'package:inference/pages/computer_vision/widgets/model_properties.dart'; +import 'package:inference/pages/models/widgets/grid_container.dart'; +import 'package:inference/project.dart'; +import 'package:inference/providers/image_inference_provider.dart'; +import 'package:inference/theme_fluent.dart'; +import 'package:inference/widgets/device_selector.dart'; +import 'package:inference/widgets/controls/drop_area.dart'; +import 'package:inference/widgets/controls/no_outline_button.dart'; +import 'package:inference/widgets/canvas/canvas.dart'; +import 'package:provider/provider.dart'; + +import 'dart:ui' as ui; + + +class LiveInference extends StatefulWidget { + final Project project; + + const LiveInference({required this.project, super.key}); + + @override + State createState() => _LiveInferenceState(); +} + +class _LiveInferenceState extends State { + Future? inferenceResult; + ui.Image? image; + + void showUploadMenu() async { + FilePickerResult? result = await FilePicker.platform.pickFiles(type: FileType.image); + + if (result != null) { + uploadFile(result.files.single.path!); + } + } + + void uploadFile(String path) async { + setState(() { + image = null; + inferenceResult = null; + }); + + Uint8List imageData = File(path).readAsBytesSync(); + final inferenceProvider = Provider.of(context, listen: false); + final uiImage = await decodeImageFromList(imageData); + setState(() { + image = uiImage; + inferenceResult = inferenceProvider.infer(imageData, SerializationOutput(json: true)); + }); + } + + @override + Widget build(BuildContext context) { + final theme = FluentTheme.of(context); + + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + children: [ + SizedBox( + height: 64, + child: GridContainer( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + children: [ + DropDownButton( + buttonBuilder: (context, callback) { + return NoOutlineButton( + onPressed: callback, + child: Row( + children: [ + const Text("Choose image file"), + const Padding( + padding: EdgeInsets.only(left: 8), + child: Icon(FluentIcons.chevron_down, size: 12), + ), + ], + ), + ); + }, + items: [ + MenuFlyoutItem(text: const Text("Choose image file"), onPressed: showUploadMenu), + //MenuFlyoutItem(text: const Text("Camera"), onPressed: () {}), + MenuFlyoutItem(text: const Text("Sample image"), onPressed: () { + uploadFile(widget.project.samplePath()); + }), + ] + ), + const DeviceSelector(), + ], + ), + ), + ), + ), + Expanded( + child: GridContainer( + color: backgroundColor.of(theme), + child: Builder( + builder: (context) { + return DropArea( + type: "image", + showChild: inferenceResult != null, + onUpload: (String file) { uploadFile(file); }, + extensions: const ["jpg", "jpeg", "bmp", "png", "tif", "tiff"], + child: Padding( + padding: const EdgeInsets.all(8.0), + child: FutureBuilder( + future: inferenceResult, + builder: (context, snapshot) { + if(snapshot.hasData) { + return Canvas( + image: image!, + annotations: snapshot.data!.parseAnnotations(), + labelDefinitions: widget.project.labelDefinitions, + ); + } + return Center(child: Image.asset('images/intel-loading.gif', width: 100)); + } + ), + ), + ); + } + ), + ), + ) + ], + ), + ), + ModelProperties(project: widget.project), + ], + ); + } +} diff --git a/lib/pages/computer_vision/providers/batch_inference_provider.dart b/lib/pages/computer_vision/providers/batch_inference_provider.dart new file mode 100644 index 00000000..7e7ffc95 --- /dev/null +++ b/lib/pages/computer_vision/providers/batch_inference_provider.dart @@ -0,0 +1,155 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:csv/csv.dart'; +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:inference/interop/openvino_bindings.dart'; +import 'package:inference/providers/image_inference_provider.dart'; +import 'package:mime/mime.dart'; +import 'package:path/path.dart'; + +bool isImage(String path) { + final mimeType = lookupMimeType(path); + if (mimeType == null) { + return false; + } + return mimeType.startsWith('image/'); +} + +class Progress { + int current = 0; + final int total; + + Progress(this.total); + + double percentage() { + return current.toDouble() / total; + } +} +enum BatchInferenceState { Ready, Running, Done } + +class BatchInferenceProvider extends ChangeNotifier { + ImageInferenceProvider imageInference; + bool _forceStop = false; + + String? _sourceFolder; + + String? get sourceFolder => _sourceFolder; + set sourceFolder(String? v) { + _sourceFolder = v; + notifyListeners(); + } + + String? _destinationFolder; + + String? get destinationFolder => _destinationFolder; + set destinationFolder(String? v) { + _destinationFolder = v; + notifyListeners(); + } + + SerializationOutput _output; + + SerializationOutput get output => _output; + set output(SerializationOutput v) { + _output = v; + notifyListeners(); + } + + Progress? _progress; + Progress? get progress => _progress; + set progress(Progress? p) { + _progress = p; + notifyListeners(); + } + + void imageProcessed() { + _progress?.current += 1; + notifyListeners(); + } + + BatchInferenceState get state { + if (progress == null ) { + return BatchInferenceState.Ready; + } else if (progress!.current < progress!.total) { + return BatchInferenceState.Running; + } else { + return BatchInferenceState.Done; + } + } + + BatchInferenceProvider(this.imageInference, this._output); + + void stop() { + _forceStop = true; + } + + void start() async { + _forceStop = false; + await imageInference.loaded.future; + final platformContext = Context(style: Style.platform); + List> rows = []; + const encoder = JsonEncoder.withIndent(" "); + const converter = CsvToListConverter(); + + final files = await getFiles(); + + progress = Progress(files.length); + + for (final file in files) { + if (_forceStop) { + progress = null; + break; + } + final outputFilename = platformContext.basename(file.path); + Uint8List imageData = File(file.path).readAsBytesSync(); + final inferenceResult = await imageInference.infer(imageData, output); + await Future.delayed(Duration.zero); // For some reason ui does not update even though it's running in Isolate. This gives the UI time to run that code. + final outputPath = platformContext.join(destinationFolder!, outputFilename); + if (output.overlay) { + final outputFile = File(outputPath); + final decodedImage = base64Decode(inferenceResult.overlay!); + outputFile.writeAsBytes(decodedImage); + } + if (output.csv) { + var csvOutput = converter.convert(inferenceResult.csv); + rows.addAll(csvOutput.map((row) { + row.insert(0, outputFilename); + return row; + })); + } + if (output.json) { + final outputFile = File(setExtension(outputPath, ".json")); + outputFile.writeAsString(encoder.convert(inferenceResult.json)); + } + + imageProcessed(); + } + + if (output.csv) { + List columns = ["filename", "label_name", "label_id", "probability", "shape_type", "x", "y", "width", "height", "area", "angle"]; + rows.insert(0, columns); + const converter = ListToCsvConverter(); + final outputPath = platformContext.join(destinationFolder!, "predictions.csv"); + File(outputPath).writeAsStringSync(converter.convert(rows)); + } + print("done"); + } + + bool validSetup() { + return sourceFolder != null && + destinationFolder != null && + output.any(); + } + + Future> getFiles() async { + if (!validSetup()){ + throw Exception("Setup was invalid"); + } + final dir = Directory(sourceFolder!); + final listener = dir.list(recursive: true); + return listener.where((b) => isImage(b.path)).toList(); + } + +} diff --git a/lib/pages/computer_vision/widgets/device_selector.dart b/lib/pages/computer_vision/widgets/device_selector.dart new file mode 100644 index 00000000..b74bed27 --- /dev/null +++ b/lib/pages/computer_vision/widgets/device_selector.dart @@ -0,0 +1,64 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:inference/providers/preference_provider.dart'; +import 'package:provider/provider.dart'; +import 'package:collection/collection.dart'; + +class DeviceSelector extends StatefulWidget { + const DeviceSelector({super.key}); + + @override + State createState() => _DeviceSelectorState(); +} + +class _DeviceSelectorState extends State { + String? selectedDevice; + + @override + void initState() { + super.initState(); + selectedDevice = Provider.of(context, listen: false).device; + } + + @override + Widget build(BuildContext context) { + return Consumer(builder: (context, preferences, child) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Text("Device", + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ComboBox( + value: selectedDevice, + items: PreferenceProvider.availableDevices.map>((e) { + return ComboBoxItem( + value: e.id, + child: Text(e.name), + ); + }).toList(), + onChanged: (v) { + setState(() { + selectedDevice = v; + if (v != null) { + preferences.device = v; + } + }); + }, + ), + ], + ), + ], + ); + } + ); + } +} diff --git a/lib/pages/computer_vision/widgets/folder_selector.dart b/lib/pages/computer_vision/widgets/folder_selector.dart new file mode 100644 index 00000000..b99568e5 --- /dev/null +++ b/lib/pages/computer_vision/widgets/folder_selector.dart @@ -0,0 +1,101 @@ +import 'dart:io'; + +import 'package:desktop_drop/desktop_drop.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:path/path.dart'; + +class FolderSelector extends StatefulWidget { + final String label; + final void Function(String) onSubmit; + const FolderSelector({ + super.key, + required this.onSubmit, + required this.label, + }); + + @override + State createState() => _FolderSelectorState(); +} + +class _FolderSelectorState extends State { + final controller = TextEditingController(); + + void showUploadMenu() async { + final result = await FilePicker.platform.getDirectoryPath(); + if (result != null) { + setPath(result.toString()); + } + } + + void setPath(String path) { + controller.text = path; + widget.onSubmit(path); + } + + @override + void dispose() { + super.dispose(); + controller.dispose(); + } + + @override + Widget build(BuildContext context) { + bool disable = Platform.isMacOS; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Text(widget.label, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + DropTarget( + onDragDone: (details) { + final platformContext = Context(style: Style.platform); + if (Directory(details.files.first.path).existsSync()) { + // folder is dragged in + setPath(details.files.first.path); + } else { + // file was dragged in, taking file dir. + final directory = platformContext.dirname(details.files.first.path); + setPath(directory); + } + }, + child: Row( + children: [ + Expanded(child: TextBox( + enabled: !disable, + controller: controller, + placeholder: "Drop ${widget.label.toLowerCase()} in", + onChanged: widget.onSubmit, + )), + Padding( + padding: const EdgeInsets.only(left: 8), + child: Button( + onPressed: showUploadMenu, + child: Padding( + padding: const EdgeInsets.all(2), + child: Row( + children: [ + const Padding( + padding: EdgeInsets.only(right: 8), + child: Icon(FluentIcons.fabric_folder), + ), + const Text("Select"), + ] + ), + ) + ), + ) + ], + ), + ), + ], + ); + } +} diff --git a/lib/pages/computer_vision/widgets/horizontal_rule.dart b/lib/pages/computer_vision/widgets/horizontal_rule.dart new file mode 100644 index 00000000..3eb59136 --- /dev/null +++ b/lib/pages/computer_vision/widgets/horizontal_rule.dart @@ -0,0 +1,25 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:inference/theme_fluent.dart'; + +class HorizontalRule extends StatelessWidget { + const HorizontalRule({super.key}); + + @override + Widget build(BuildContext context) { + final theme = FluentTheme.of(context); + + return Padding( + padding: const EdgeInsets.symmetric(vertical: 20), + child: Container( + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: borderColor.of(theme), + width: 1, + ) + ) + ), + ), + ); + } +} diff --git a/lib/pages/computer_vision/widgets/model_properties.dart b/lib/pages/computer_vision/widgets/model_properties.dart new file mode 100644 index 00000000..5d7e932d --- /dev/null +++ b/lib/pages/computer_vision/widgets/model_properties.dart @@ -0,0 +1,102 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:inference/project.dart'; +import 'package:inference/theme_fluent.dart'; +import 'package:inference/pages/models/widgets/grid_container.dart'; +import 'package:intl/intl.dart'; +import 'package:inference/utils.dart'; + +class ModelProperties extends StatelessWidget { + final Project project; + const ModelProperties({super.key, required this.project}); + + @override + Widget build(BuildContext context) { + Locale locale = Localizations.localeOf(context); + final formatter = NumberFormat.percentPattern(locale.languageCode); + + return SizedBox( + width: 280, + child: GridContainer( + padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text("Model parameters", style: TextStyle( + fontSize: 20, + )), + Container( + padding: const EdgeInsets.only(top: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ModelProperty( + title: "Model name", + value: project.name, + ), + ModelProperty( + title: "Task", + value: project.taskName(), + ), + ModelProperty( + title: "Architecture", + value: project.architecture, + ), + ModelProperty( + title: "Size", + value: project.size?.readableFileSize() ?? "", + ), + Builder( + builder: (context) { + if (project.tasks.first.performance == null) { + return Container(); + } + return ModelProperty( + title: "Accuracy", + value: formatter.format(project.tasks.first.performance!.score) + ); + } + ), + ], + ), + ) + ], + ) + ), + ); + } +} + +class ModelProperty extends StatelessWidget { + final String title; + final String value; + + const ModelProperty({ + required this.title, + required this.value, + super.key}); + + @override + Widget build(BuildContext context) { + final theme = FluentTheme.of(context); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 4), + child: Text(title, style: const TextStyle( + fontWeight: FontWeight.w600, + fontSize: 14, + )), + ), + Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Text(value, style: TextStyle( + fontSize: 16, + color: subtleTextColor.of(theme), + )), + ), + ] + ); + } +} diff --git a/lib/pages/computer_vision/widgets/output_selector.dart b/lib/pages/computer_vision/widgets/output_selector.dart new file mode 100644 index 00000000..87607637 --- /dev/null +++ b/lib/pages/computer_vision/widgets/output_selector.dart @@ -0,0 +1,114 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:inference/pages/computer_vision/providers/batch_inference_provider.dart'; +import 'package:provider/provider.dart'; + +class OutputSelector extends StatefulWidget { + const OutputSelector({super.key}); + + @override + State createState() => _OutputSelectorState(); +} + +class _OutputSelectorState extends State { + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Consumer(builder: (context, batchInference, child) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Text("Outputs", + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + OutputToggle( + name: "Overlay image", + initialValue: batchInference.output.overlay, + onToggle: (v) { + setState(() { + batchInference.output = batchInference.output..overlay = v; + }); + }, + ), + OutputToggle( + name: "CSV", + initialValue: batchInference.output.csv, + onToggle: (v) { + setState(() { + batchInference.output = batchInference.output..csv = v; + }); + }, + ), + OutputToggle( + name: "JSON", + initialValue: batchInference.output.json, + onToggle: (v) { + setState(() { + batchInference.output = batchInference.output..json = v; + }); + }, + ), + ], + ); + } + ); + } +} + +class OutputToggle extends StatefulWidget { + final String name; + final bool initialValue; + final Function(bool)? onToggle; + + const OutputToggle({ + super.key, + required this.name, + this.onToggle, + this.initialValue = false, + }); + + @override + State createState() => _OutputToggleState(); +} + +class _OutputToggleState extends State { + late bool checked; + + @override + void initState() { + super.initState(); + checked = widget.initialValue; + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 14), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(widget.name), + ToggleSwitch( + checked: checked, + onChanged: (bool val) { + setState(() { + checked = val; + widget.onToggle?.call(val); + }); + }, + ) + ] + ), + ); + } +} diff --git a/lib/pages/download_model/download_model.dart b/lib/pages/download_model/download_model.dart new file mode 100644 index 00000000..a6fb94de --- /dev/null +++ b/lib/pages/download_model/download_model.dart @@ -0,0 +1,229 @@ +import 'dart:math'; + +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:go_router/go_router.dart'; +import 'package:inference/deployment_processor.dart'; +import 'package:inference/project.dart'; +import 'package:inference/providers/download_provider.dart'; +import 'package:inference/providers/project_provider.dart'; +import 'package:inference/public_models.dart'; +import 'package:inference/theme_fluent.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; + +String formatBytes(int bytes) { + return "${NumberFormat("#,##0").format(bytes / pow(1024, 2))} MB"; +} + + +class DownloadPage extends StatelessWidget { + final PublicProject project; + const DownloadPage({super.key, required this.project}); + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider( + create: (_) => DownloadProvider(), + child: DownloadModelPage(project: project), + ); + } +} + +class DownloadModelPage extends StatefulWidget { + final PublicProject project; + const DownloadModelPage({super.key, required this.project}); + + @override + State createState() => _DownloadModelPageState(); +} + +class _DownloadModelPageState extends State { + @override + void initState() { + super.initState(); + startDownload(); + } + + void startDownload() async { + final downloadProvider = Provider.of(context, listen: false); + final projectProvider = Provider.of(context, listen: false); + final router = GoRouter.of(context); + late Map files; + + try { + files = await listDownloadFiles(widget.project); + } catch (e) { + await showDialog(context: context, builder: (BuildContext context) => ContentDialog( + title: const Text('Model was not found'), + actions: [ + Button( + onPressed: () { + router.canPop() ? router.pop() : router.go('/home'); + }, + child: const Text('Close'), + ), + ], + )); + return; + } + + try { + downloadProvider.onCancel = () => deleteProjectData(widget.project); + await downloadProvider.queue(files, widget.project.modelInfo?.collection.token); + projectProvider.addProject(widget.project); + await getAdditionalModelInfo(widget.project); + projectProvider.completeLoading(widget.project); + router.go("/models/inference", extra: widget.project); + } catch(e) { + if (mounted) { + await showDialog(context: context, builder: (BuildContext context) => ContentDialog( + title: Text('An error occurred trying to download ${widget.project.name}'), + content: Text(e.toString()), + actions: [ + Button( + onPressed: () { + router.canPop() ? router.pop() : router.go('/home'); + }, + child: const Text('Close'), + ), + ], + )); + } + } + } + + @override + Widget build(BuildContext context) { + final theme = FluentTheme.of(context); + return ScaffoldPage( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8.0), + header: Container( + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: theme.resources.controlStrokeColorDefault, + width: 1.0 + ) + ) + ), + height: 56, + padding: const EdgeInsets.symmetric(horizontal: 12.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row( + children: [ + Padding( + padding: const EdgeInsets.only(left: 12.0, bottom: 8), + child: ClipRRect( + borderRadius: BorderRadius.circular(4.0), + child: Container( + width: 40, + height: 40, + decoration: BoxDecoration( + image: DecorationImage( + image: widget.project.thumbnailImage(), + fit: BoxFit.fitWidth), + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text(widget.project.name, + style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + ), + ], + ), + Button(child: const Text("Close"), onPressed: () { + GoRouter.of(context).canPop() ? GoRouter.of(context).pop() : GoRouter.of(context).go('/home'); + }), + ], + ), + ), + content: Row( + children: [ + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: Consumer(builder: (context, downloadProvider, child) { + final stats = downloadProvider.stats; + return Column( + children: [ + ProgressRing( + value: stats.percentage * 100, + strokeWidth: 8, + ), + SizedBox( + width: 140, + child: Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(formatBytes(stats.received), textAlign: TextAlign.end,), + const Text("/"), + Text(formatBytes(stats.total)) + ], + ), + ), + ), + const Padding( + padding: EdgeInsets.all(8.0), + child: Text("Downloading model weights"), + ) + ] + ); + } + ), + ) + ], + ), + ), + Container( + width: 280, + decoration: BoxDecoration( + border: Border( + left: BorderSide( + color: theme.resources.controlStrokeColorDefault, + width: 1.0, + ), + ), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Padding( + padding: EdgeInsets.symmetric(vertical: 18.0), + child: Text("Model parameters", style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600)), + ), + const Padding( + padding: EdgeInsets.only(top: 16), + child: Text("Model name", style: TextStyle(fontSize: 14),), + ), + Padding(padding: const EdgeInsets.only(top: 4), + child: Text(widget.project.modelId, style: const TextStyle(fontSize: 14, color: foreground3Color),), + ), + const Padding(padding: EdgeInsets.only(top: 16), + child: Text("Task", style: TextStyle(fontSize: 14),), + ), + Padding(padding: const EdgeInsets.only(top: 4), + child: Text(widget.project.taskName(), style: const TextStyle(fontSize: 14, color: foreground3Color),), + ), + ], + ), + ), + ), + ], + ) + ); + } +} diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart new file mode 100644 index 00000000..b9a507ad --- /dev/null +++ b/lib/pages/home/home.dart @@ -0,0 +1,146 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:inference/pages/home/widgets/featured_card.dart'; +import 'package:inference/pages/models/widgets/model_card.dart'; +import 'package:inference/importers/manifest_importer.dart'; +import 'package:inference/widgets/fixed_grid.dart'; +import 'package:inference/widgets/import_model_button.dart'; +import 'package:inference/providers/project_provider.dart'; +import 'package:provider/provider.dart'; + +class HomePage extends StatefulWidget { + const HomePage({super.key}); + + @override + State createState() => _HomePageState(); +} + +class _HomePageState extends State { + late Future> popularModelsFuture; + + @override + void initState() { + super.initState(); + final importer = ManifestImporter('assets/manifest.json'); + popularModelsFuture = importer.loadManifest().then((_) => importer.getPopularModels()); + } + + @override + Widget build(BuildContext context) { + return ScaffoldPage.scrollable( + padding: const EdgeInsets.all(0), + children: [ + Stack( + alignment: Alignment.bottomCenter, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 48), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ConstrainedBox( + constraints: const BoxConstraints(maxHeight: 400), + child: Stack( + alignment: Alignment.topLeft, + children: [ + Image.asset("images/banner.png", fit: BoxFit.cover, width: double.infinity, height: 400,), + Padding( + padding: const EdgeInsets.all(24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SvgPicture.asset("images/openvino_logo.svg", width: 81), + const Text("TestDrive", + style: TextStyle( + color: Colors.white, + fontSize: 32, + ) + ), + ], + ), + ), + ], + ), + ), + ], + ), + ), + FutureBuilder>( + future: popularModelsFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const ProgressRing(); + } else if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else if (!snapshot.hasData || snapshot.data!.isEmpty) { + return const Text('No popular models available'); + } else { + final popularModels = snapshot.data!; + return HorizontalScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 4), + child: Row( + children: popularModels.map((model) => Padding( + padding: EdgeInsets.only( + right: popularModels.indexOf(model) == popularModels.length - 1 ? 0 : 32, + ), + child: FeaturedCard(model: model), + )).toList(), + ), + ), + ); + } + }, + ), + ], + ), + Center( + child: Padding( + padding: const EdgeInsets.only(left: 32, right: 32, top: 32), + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 1228), + child: Consumer(builder: (context, value, child) { + return FixedGrid( + tileWidth: 268, + centered: true, + spacing: 36, + itemCount: value.projects.length, + header: Padding( + padding: const EdgeInsets.symmetric(vertical: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text('My models', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + Row( + children: [ + IconButton(icon: const Icon(FluentIcons.filter), onPressed: () {}), + IconButton(icon: const Icon(FluentIcons.sort_down), onPressed: () {}), + ConstrainedBox( + constraints: const BoxConstraints(minHeight: 24), + child: const Divider(direction: Axis.vertical,style: DividerThemeData( + verticalMargin: EdgeInsets.symmetric(horizontal: 8), + ),), + ), + const ImportModelButton(), + ], + ) + ], + ), + ), + itemBuilder: (context, index) { + return ModelCard(project: value.projects.elementAt(index)); + } + ); + }), + ), + ), + ), + ], + ); + } +} diff --git a/lib/pages/home/widgets/featured_card.dart b/lib/pages/home/widgets/featured_card.dart new file mode 100644 index 00000000..c756ac18 --- /dev/null +++ b/lib/pages/home/widgets/featured_card.dart @@ -0,0 +1,97 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:inference/importers/manifest_importer.dart'; +import 'package:inference/widgets/elevation.dart'; +import 'package:go_router/go_router.dart'; + +class FeaturedCard extends StatelessWidget { + final Model model; + const FeaturedCard({required this.model, super.key}); + + void downloadModel(BuildContext context) { + model.convertToProject().then((project) { + if (context.mounted) { + GoRouter.of(context).go('/models/download', extra: project); + } + }); + } + + @override + Widget build(BuildContext context) { + final theme = FluentTheme.of(context); + return Elevation( + backgroundColor: theme.cardColor, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), + elevation: 4.0, + child: Container( + decoration: BoxDecoration( + color: theme.cardColor, + borderRadius: const BorderRadius.all(Radius.circular(4)), + ), + child: SizedBox( + width: 220, + height: 248, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox( + width: 80, + height: 80, + child: model.thumbnail, + ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 12), + decoration: const BoxDecoration( + shape: BoxShape.rectangle, + borderRadius: BorderRadius.all(Radius.circular(8)), + color: Color(0x11000000), + ), + child: Text(model.kind.toUpperCase(), + style: const TextStyle( + fontSize: 12, + ) + ), + ), + ], + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 12), + child: Text(model.name, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 4), + child: Text(model.description, style: const TextStyle(fontSize: 12)), + ), + ], + ), + Align( + alignment: Alignment.centerRight, + child: Padding( + padding: const EdgeInsets.only(top: 2), + child: IconButton(icon: const Icon(FluentIcons.pop_expand, size: 14), onPressed: () => downloadModel(context)), + ), + ), + ], + ), + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/pages/import/import.dart b/lib/pages/import/import.dart new file mode 100644 index 00000000..82af278c --- /dev/null +++ b/lib/pages/import/import.dart @@ -0,0 +1,183 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:go_router/go_router.dart'; +import 'package:inference/pages/import/widgets/badge.dart'; +import 'package:inference/pages/import/widgets/model_card.dart'; +import 'package:inference/widgets/controls/search_bar.dart'; +import 'package:inference/widgets/controls/dropdown_multiple_select.dart'; +import 'package:inference/importers/manifest_importer.dart'; +import 'package:inference/widgets/fixed_grid.dart'; + +class ImportPage extends StatefulWidget { + const ImportPage({super.key}); + + @override + _ImportPageState createState() => _ImportPageState(); +} + +class _ImportPageState extends State { + List selectedOptimizations = []; + String? searchValue; + late Future> allModelsFuture; + late Model? selectedModel; + + @override + void initState() { + super.initState(); + final importer = ManifestImporter('assets/manifest.json'); + allModelsFuture = importer.loadManifest().then((_) => importer.getAllModels()); + selectedModel = null; + } + + List filterModels(List models) { + var filteredModels = models; + if (searchValue != null && searchValue!.isNotEmpty) { + filteredModels = filteredModels.where((model) => model.name.toLowerCase().contains(searchValue!.toLowerCase())).toList(); + } + if (selectedOptimizations.isNotEmpty) { + filteredModels = filteredModels.where((model) => selectedOptimizations.contains(model.optimizationPrecision)).toList(); + } + return filteredModels; + } + + @override + Widget build(BuildContext context) { + final theme = FluentTheme.of(context); + final router = GoRouter.of(context); + return ScaffoldPage.scrollable( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8.0), + header: Container( + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: theme.resources.controlStrokeColorDefault, + width: 1.0 + ) + ) + ), + padding: const EdgeInsets.symmetric(horizontal: 12.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Row(children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: 8.0, vertical: 18), + child: Text('Import model', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + ), + ],), + Row( + children: [ + FilledButton(onPressed: selectedModel == null ? (null) : () { + selectedModel?.convertToProject().then((project) { + router.go('/models/download', extra: project); + }); + + }, child: const Text('Import selected model'),), + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Button(child: const Text('Close'), onPressed: () { router.pop(); }), + ) + ], + ) + ], + ), + ), + children: + [ + Center( + child: ConstrainedBox(constraints: const BoxConstraints(maxWidth: 1228), + child: Column( + children: [ + Row( + children: [ + ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 280), + child: Semantics( + label: 'Find a model', + child: SearchBar(onChange: (value) { setState(() { + searchValue = value; + }); }, placeholder: 'Find a model',), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 8), + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 184), + child: DropdownMultipleSelect( + items: const ['int4', 'int8', 'fp16'], + selectedItems: selectedOptimizations, + onChanged: (value) { + if (!value.contains(selectedModel?.optimizationPrecision)) { + selectedModel = null; + } + setState(() { + selectedOptimizations = value; + }); + }, + placeholder: 'Select optimizations', + ), + ), + ) + ], + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 2), + child: SizedBox( + height: 28, + width: double.infinity, + child: Align( + alignment: Alignment.centerLeft, + child: Wrap( + spacing: 8, + children: selectedOptimizations.map((opt) { + return Badge(text: opt, onDelete: () { + if (opt == selectedModel?.optimizationPrecision && selectedOptimizations.length > 1) { + selectedModel = null; + } + setState(() { + selectedOptimizations.remove(opt); + }); + }); + }).toList(), + ), + ), + ), + ), + FutureBuilder>( + future: allModelsFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const ProgressRing(); + } else if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else if (!snapshot.hasData || snapshot.data!.isEmpty) { + return const Text('No models available'); + } else { + var allModels = filterModels(snapshot.data!); + return FixedGrid( + tileWidth: 226, + spacing: 24, + centered: true, + itemCount: allModels.length, + itemBuilder: (context, index) => ModelCard( + model: allModels[index], + checked: selectedModel == allModels[index], + onChecked: (value) { + setState(() { + selectedModel = value ? allModels[index] : null; + }); + }, + ), + ); + } + }, + ), + ], + ), + ), + ) + ] + ); + } +} diff --git a/lib/pages/import/widgets/badge.dart b/lib/pages/import/widgets/badge.dart new file mode 100644 index 00000000..191fa9f0 --- /dev/null +++ b/lib/pages/import/widgets/badge.dart @@ -0,0 +1,48 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:inference/theme_fluent.dart'; + +class Badge extends StatelessWidget { + final String text; + final VoidCallback onDelete; + + const Badge({ + super.key, + required this.text, + required this.onDelete, + }); + + @override + Widget build(BuildContext context) { + final theme = FluentTheme.of(context); + return AnimatedContainer( + duration: theme.fastAnimationDuration, + curve: theme.animationCurve, + padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 6.0), + decoration: BoxDecoration( + color: theme.brightness == Brightness.light ? cosmos.lightest : darkCosmos, + borderRadius: BorderRadius.circular(4.0), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + text, + style: TextStyle(color: theme.brightness == Brightness.light ? darkCosmos : cosmos), + ), + const SizedBox(width: 8.0), + MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + onTap: onDelete, + child: Icon( + FluentIcons.clear, + size: 12.0, + color: theme.brightness == Brightness.light ? darkCosmos : cosmos, + ), + ), + ), + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/pages/import/widgets/model_card.dart b/lib/pages/import/widgets/model_card.dart new file mode 100644 index 00000000..8fca5f5d --- /dev/null +++ b/lib/pages/import/widgets/model_card.dart @@ -0,0 +1,94 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:inference/importers/manifest_importer.dart'; +import 'package:inference/pages/models/widgets/model_property.dart'; +import 'package:inference/widgets/elevation.dart'; + +class ModelCard extends StatelessWidget { + final Model model; + final bool checked; + final ValueChanged onChecked; + + const ModelCard({ + required this.model, + required this.checked, + required this.onChecked, + super.key, + }); + + @override + Widget build(BuildContext context) { + final theme = FluentTheme.of(context); + return GestureDetector( + onTap: () { onChecked(!checked); }, + child: Elevation( + backgroundColor: theme.cardColor, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), + elevation: checked ? 16 : 4, + child: AnimatedContainer( + curve: theme.animationCurve, + duration: theme.mediumAnimationDuration, + decoration: BoxDecoration( + color: checked ? theme.inactiveBackgroundColor.withOpacity(0.5) : theme.cardColor, + borderRadius: const BorderRadius.all(Radius.circular(4)), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AspectRatio( + aspectRatio: 7/4, + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: model.thumbnail.image, + fit: BoxFit.cover, + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 12), + child: Text( + model.name, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + fontWeight: FontWeight.bold, + ), + ), + ), + Text( + model.description, + maxLines: 3, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + height: 1.5, + ), + ), + ], + ), + ), + const Spacer(), + Padding( + padding: const EdgeInsets.only(left: 8.0, right: 8.0, bottom: 8.0), + child: Wrap( + spacing: 4.0, + runSpacing: 4.0, + children: [ + ModelProperty(name: "Optimization", value: model.optimizationPrecision), + ModelProperty(name: "Size", value: model.readableFileSize), + ModelProperty(name: "Task", value: model.task), + ], + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/pages/models/inference.dart b/lib/pages/models/inference.dart new file mode 100644 index 00000000..9b8cbecb --- /dev/null +++ b/lib/pages/models/inference.dart @@ -0,0 +1,26 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:inference/pages/computer_vision/computer_vision.dart'; +import 'package:inference/pages/text_generation/text_generation.dart'; +import 'package:inference/pages/text_to_image/text_to_image_page.dart'; +import 'package:inference/pages/transcription/transcription.dart'; +import 'package:inference/project.dart'; + +class InferencePage extends StatelessWidget { + final Project project; + const InferencePage(this.project, {super.key}); + + @override + Widget build(BuildContext context) { + switch(project.type){ + case ProjectType.image: + return ComputerVisionPage(project); + case ProjectType.text: + return TextGenerationPage(project); + case ProjectType.speech: + return TranscriptionPage(project); + case ProjectType.textToImage: + return TextToImagePage(project); + } + } + +} diff --git a/lib/pages/models/models.dart b/lib/pages/models/models.dart new file mode 100644 index 00000000..fc25021d --- /dev/null +++ b/lib/pages/models/models.dart @@ -0,0 +1,87 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:inference/pages/models/widgets/grid_container.dart'; +import 'package:inference/pages/models/widgets/model_filter.dart'; +import 'package:inference/pages/models/widgets/model_list.dart'; +import 'package:inference/providers/project_filter_provider.dart'; +import 'package:inference/theme_fluent.dart'; +import 'package:inference/widgets/import_model_button.dart'; +import 'package:provider/provider.dart'; + +class ModelsPage extends StatefulWidget { + const ModelsPage({super.key}); + + @override + State createState() => _ModelsPageState(); +} + +class _ModelsPageState extends State { + @override + Widget build(BuildContext context) { + final theme = FluentTheme.of(context); + + return ChangeNotifierProvider( + create: (_) => ProjectFilterProvider(), + child: ScaffoldPage( + padding: const EdgeInsets.all(0), + content: Row( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SizedBox( + width: 280, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + GridContainer( + color: backgroundColor.of(theme), + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(8), + ), + padding: const EdgeInsets.all(16), + child: const Text("My Models", + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w500, + ), + ), + ), + Expanded( + child: GridContainer( + color: backgroundColor.of(theme), + padding: const EdgeInsets.all(13), + child: const ModelFilter() + ), + ), + ], + ), + ), + Expanded( + child: Column( + children: [ + GridContainer( + color: theme.scaffoldBackgroundColor, + padding: const EdgeInsets.all(13), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Consumer(builder: (context, projectProvider, child) { + return Text(projectProvider.option?.name ?? "", + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.w500, + ), + ); + }), + const ImportModelButton(), + ], + ), + ), + const Expanded(child: ModelList()), + ], + ), + ), + ], + ) + ), + ); + } +} diff --git a/lib/pages/models/widgets/grid_container.dart b/lib/pages/models/widgets/grid_container.dart new file mode 100644 index 00000000..75002b9c --- /dev/null +++ b/lib/pages/models/widgets/grid_container.dart @@ -0,0 +1,38 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:inference/theme_fluent.dart'; + +class GridContainer extends StatelessWidget { + final Widget? child; + final EdgeInsets? padding; + final Color? color; + final bool? borderTop; + final bool? borderLeft; + final BorderRadiusGeometry? borderRadius; + + const GridContainer({super.key, this.child, this.padding, this.color, this.borderTop, this.borderLeft, this.borderRadius}); + + @override + Widget build(BuildContext context) { + final theme = FluentTheme.of(context); + + return Container( + padding: padding, + decoration: BoxDecoration( + borderRadius: borderRadius, + color: color, + border: Border( + top: borderTop == false ? BorderSide.none : BorderSide( + color: borderColor.of(theme), + width: 1, + ), + left: borderLeft == false ? BorderSide.none : BorderSide( + color: borderColor.of(theme), + width: 1, + ), + ) + ), + child: child + ); + } + +} diff --git a/lib/pages/models/widgets/model_card.dart b/lib/pages/models/widgets/model_card.dart new file mode 100644 index 00000000..d6817f97 --- /dev/null +++ b/lib/pages/models/widgets/model_card.dart @@ -0,0 +1,120 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:go_router/go_router.dart'; +import 'package:inference/pages/models/widgets/model_property.dart'; +import 'package:inference/project.dart'; +import 'package:inference/utils.dart'; +import 'package:inference/widgets/elevation.dart'; +import 'package:intl/intl.dart'; + +class ModelCard extends StatefulWidget { + final Project project; + const ModelCard({super.key, required this.project}); + + @override + State createState() => _ModelCardState(); +} + +class _ModelCardState extends State{ + bool isHovered = false; + + @override + Widget build(BuildContext context) { + final theme = FluentTheme.of(context); + + return GestureDetector( + onTap: () { + if (widget.project.isDownloaded) { + GoRouter.of(context).go("/models/inference", extra: widget.project); + } else { + GoRouter.of(context).go("/models/download", extra: widget.project); + } + }, + child: MouseRegion( + cursor: SystemMouseCursors.click, + child: Elevation( + backgroundColor: theme.cardColor, + elevation: 4, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), + child: Container( + decoration: BoxDecoration( + shape: BoxShape.rectangle, + borderRadius: const BorderRadius.all(Radius.circular(4)), + border: theme.brightness.isDark + ? Border.all( + color: const Color(0xFF464646), + width: 1, + ) + : null, + color: theme.cardColor, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AspectRatio( + aspectRatio: 5/4, + child: ClipRRect( + borderRadius: const BorderRadius.only(topLeft: Radius.circular(4), topRight: Radius.circular(4)), + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: widget.project.thumbnailImage(), + fit: BoxFit.cover, + ), + ), + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(widget.project.name, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + ) + ), + Padding( + padding: const EdgeInsets.only(top: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ModelProperty(name: "Task", value: widget.project.taskName()), + ModelProperty(name: "Architecture", value: widget.project.architecture), + Row( + children: [ + ModelProperty(name: "Size", value: widget.project.size?.readableFileSize() ?? ""), + Builder( + builder: (context) { + if (widget.project is GetiProject && widget.project.tasks.first.performance != null) { + Locale locale = Localizations.localeOf(context); + final formatter = NumberFormat.percentPattern(locale.languageCode); + return ModelProperty( + name: "Accuracy", + value: formatter.format(widget.project.tasks.first.performance!.score)); + } + return Container(); + } + ), + ], + ), + ], + ), + ) + ], + ), + ), + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/pages/models/widgets/model_filter.dart b/lib/pages/models/widgets/model_filter.dart new file mode 100644 index 00000000..1682cbb6 --- /dev/null +++ b/lib/pages/models/widgets/model_filter.dart @@ -0,0 +1,134 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:inference/providers/project_filter_provider.dart'; +import 'package:provider/provider.dart'; + + + +class ModelFilter extends StatelessWidget { + const ModelFilter({super.key}); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: 200, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ...Option.filterOptions.keys.map((key) { + return Group(key, Option.filterOptions[key]!); + }), + ] + ), + ); + } +} + +class Group extends StatefulWidget { + final String name; + final List(List list, I item) { + list.remove(item); + list.insert(0, item); +} + +void moveToEnd(List list, I item) { + list.remove(item); + list.add(item); +} + +class DynamicRangeLoading { + List
sections = []; + int? size; + Map data = {}; + + DynamicRangeLoading(Section section): sections = [section], size = section.end; + + Section get activeSection => sections.first; + + // The incomplete sections will always be in front + bool get complete => activeSection.complete; + + void skipTo(int i) { + for (var section in sections) { + if (section.contains(i)) { + if (i > section.index) { + // Section has not progressed until the requested index + // Split the section and move the new section to the front + final newSection = section.split(i); + sections.insert(0, newSection); + } else { + // Section is further ahead than requested skipTo + // move section to front since that work has higher prio + if (!section.complete && section != activeSection) { + moveToFront(sections, section); + } + } + return; + } + } + + throw Exception("Out of range"); + } + + int getNextIndex() { + if (complete) { + throw Exception("Cannot get next index. All work is done"); + } + return activeSection.index; + } + + void pumpIndex() { + if (activeSection.pump()) { + //activeSection has ended + if (sections.length > 1) { + moveToEnd(sections,activeSection); + } + } + } + + Future process(Future Function(int) func) async{ + final index = getNextIndex(); + final val = await func(index); + data[index] = val; + pumpIndex(); + return val; + } + + void setData(I value) { + data[activeSection.index] = value; + activeSection.index += 1; + } +} + +class Section { + int begin; + int? end; + int index; + + Section(this.begin, this.end): index = begin; + + bool contains(int i) => begin <= i && (end == null ? true : i < end!); + + Section split(int i) { + final newSection = Section(i, end); + end = i; + return newSection; + } + + bool get complete => index == end; + + //returns false if there is still work to do in the section + bool pump() { + if (end == null || index < end!) { + index += 1; + } + return complete; + } +} diff --git a/lib/pages/transcription/widgets/paragraph.dart b/lib/pages/transcription/widgets/paragraph.dart new file mode 100644 index 00000000..c6ca4f16 --- /dev/null +++ b/lib/pages/transcription/widgets/paragraph.dart @@ -0,0 +1,98 @@ + +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:inference/theme_fluent.dart'; +import '../utils/message.dart'; + +String formatDuration(int totalSeconds) { + final duration = Duration(seconds: totalSeconds); + final minutes = duration.inMinutes; + final seconds = totalSeconds % 60; + + final minutesString = '$minutes'.padLeft(2, '0'); + final secondsString = '$seconds'.padLeft(2, '0'); + return '$minutesString:$secondsString'; +} + +class Paragraph extends StatefulWidget { + final Function(Duration)? onSeek; + final Message message; + final String? highlightedText; + + const Paragraph({super.key, required this.message, this.onSeek, this.highlightedText}); + + @override + State createState() => _ParagraphState(); +} + +class _ParagraphState extends State { + bool hover = false; + + @override + Widget build(BuildContext context) { + final theme = FluentTheme.of(context); + List pieces = []; + if (widget.highlightedText != null) { + final pattern = RegExp(widget.highlightedText!, caseSensitive: false); + final sections = widget.message.message.split(pattern); + if (sections.isNotEmpty) { + pieces.add(TextSpan(text: sections.first)); + for (int i = 1; i < sections.length; i++) { + pieces.add( + TextSpan( + text: widget.highlightedText!, + style: TextStyle(backgroundColor: theme.accentColor), + ) + ); + pieces.add(TextSpan(text: sections[i])); + } + } + } else { + pieces.add(TextSpan(text: widget.message.message)); + } + return MouseRegion( + onEnter: (_) { + setState(() => hover = true); + }, + onExit: (_) { + setState(() => hover = false); + }, + child: GestureDetector( + onTap: () { + widget.onSeek?.call(widget.message.position); + }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 4), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Align( + alignment: Alignment.bottomRight, + child: Text(formatDuration(widget.message.position.inSeconds), + style: TextStyle( + fontSize: 9, + color: subtleTextColor.of(theme), + ) + ) + ), + Container( + decoration: BoxDecoration( + color: hover ? subtleTextColor.of(theme).withOpacity(0.3) : null, + borderRadius: const BorderRadius.all(Radius.circular(4)), + ), + padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2), + child: RichText( + text: TextSpan( + style: TextStyle( + color: theme.inactiveColor + ), + children: pieces + ) + ) + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/pages/transcription/widgets/subtitles.dart b/lib/pages/transcription/widgets/subtitles.dart new file mode 100644 index 00000000..da17b0c9 --- /dev/null +++ b/lib/pages/transcription/widgets/subtitles.dart @@ -0,0 +1,60 @@ +import 'dart:async'; + +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:inference/interop/openvino_bindings.dart'; + +class Subtitles extends StatelessWidget { + const Subtitles({ + super.key, + required this.transcription, + required this.subtitleIndex, + }); + + final Map>? transcription; + final int subtitleIndex; + + static const double fontSize = 18; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(left: 8, right: 8, bottom: 60), + child: SizedBox( + height: 100, + child: Builder( + builder: (context) { + if (transcription == null ) { + return Container(); + } + if (transcription![subtitleIndex] is TranscriptionModelResponse) { + final text = (transcription![subtitleIndex] as TranscriptionModelResponse).text; + return Stack( + alignment: Alignment.bottomCenter, + children: [ + Text(text, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: fontSize, + foreground: Paint() + ..style = PaintingStyle.stroke + ..strokeWidth = 2 + ..color = Colors.black, + ) + ), + Text(text, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: fontSize, + color: Colors.white, + ) + ) + ], + ); + } + return Container(); + } + ), + ), + ); + } +} diff --git a/lib/pages/transcription/widgets/transcription.dart b/lib/pages/transcription/widgets/transcription.dart new file mode 100644 index 00000000..b02fcdc2 --- /dev/null +++ b/lib/pages/transcription/widgets/transcription.dart @@ -0,0 +1,141 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:file_picker/file_picker.dart'; +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:inference/interop/openvino_bindings.dart'; +import 'package:inference/pages/transcription/utils/message.dart'; +import 'package:inference/pages/transcription/utils/section.dart'; +import 'package:inference/pages/transcription/widgets/paragraph.dart'; +import 'package:inference/widgets/controls/search_bar.dart'; + + +class Transcription extends StatefulWidget { + final DynamicRangeLoading>? transcription; + final Function(Duration)? onSeek; + final List messages; + const Transcription({super.key, this.onSeek, this.transcription, required this.messages}); + + @override + State createState() => _TranscriptionState(); +} + +class _TranscriptionState extends State { + final List _paragraphKeys = []; + final ScrollController _scrollController = ScrollController(); + final GlobalKey scrollKey = GlobalKey(); + String? searchText; + + void saveTranscript() async { + final file = await FilePicker.platform.saveFile( + dialogTitle: "Please select an output file:", + fileName: "transcription.txt", + ); + if (file == null){ + return; + } + + String contents = ""; + final indices = widget.transcription!.data.keys.toList()..sort(); + for (int i in indices) { + final part = widget.transcription!.data[i] as TranscriptionModelResponse; + for (final chunk in part.chunks) { + contents += chunk.text; + } + } + + await File(file).writeAsString(contents); + } + + void search(String text) { + setState(() { + searchText = text; + }); + + final pattern = RegExp(text, caseSensitive: false); + int? index; + for (int i = 0; i < widget.messages.length; i++) { + if (widget.messages[i].message.contains(pattern)) { + index = i; + break; + } + + } + if (index != null){ + final context = _paragraphKeys[index].currentContext; + + if (context != null) { + final renderBox = context.findRenderObject() as RenderBox?; + if (renderBox != null) { + final position = renderBox.localToGlobal(Offset.zero, ancestor: scrollKey.currentContext?.findRenderObject()); + final offset = _scrollController.offset + position.dy; + _scrollController.animateTo( + offset, + duration: const Duration(milliseconds: 500), + curve: Curves.easeInOut, + ); + } + } + } + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(vertical: 25, horizontal: 14), + child: Row( + children: [ + SearchBar(onChange: search, placeholder: "Search in transcript",), + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Tooltip( + message: widget.transcription!.complete + ? "Download transcript" + : "Transcribing...", + child: Button( + onPressed: widget.transcription?.complete ?? false + ? () => saveTranscript() + : null, + child: const Padding( + padding: EdgeInsets.symmetric(vertical: 2), + child: Icon(FluentIcons.download), + ), + ), + ), + ) + ], + ), + ), + Expanded( + child: SingleChildScrollView( + key: scrollKey, + controller: _scrollController, + child: Padding( + padding: const EdgeInsets.only(left: 10, right: 18), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: List.generate(widget.messages.length, (index) { + // Adjusting state in render is ugly. But works. + // This is done because we need a global key but the paragraphs are added as you go. + if (_paragraphKeys.length <= index) { + _paragraphKeys.add(GlobalKey()); + } + + return Paragraph( + key: _paragraphKeys[index], + message: widget.messages[index], + highlightedText: searchText, + onSeek: widget.onSeek, + ); + + }), + ), + ), + ), + ), + ], + ); + } +} diff --git a/lib/project.dart b/lib/project.dart index 244cf1bb..4159014e 100644 --- a/lib/project.dart +++ b/lib/project.dart @@ -117,7 +117,7 @@ ProjectType parseProjectType(String name) { if (name == "image") { return ProjectType.image; } - if (name == "text"){ + if (name == "text" || name == "text-generation"){ return ProjectType.text; } if (name == "textToImage"){ @@ -127,7 +127,7 @@ ProjectType parseProjectType(String name) { return ProjectType.speech; } - throw UnimplementedError(); + throw UnimplementedError(name); } String projectTypeToString(ProjectType type) { @@ -156,6 +156,16 @@ class Project { bool isPublic; bool hasSample = false; + int? size; + + String get architecture { + if (tasks.length > 1) { + return "Task Chain"; + } + return tasks.first.architecture; + } + + List