Uygulama Dağıtımına Giriş
Uygulama dağıtımı (Application Deployment), geliştirdiğiniz masaüstü uygulamasını son kullanıcılara ulaştırma sürecidir. Bu süreç, uygulamanızın farklı işletim sistemlerinde çalışabilir hale getirilmesi, gerekli bağımlılıkların paketlenmesi ve kullanıcı dostu kurulum deneyimi sağlanmasını içerir.
Yapay zeka destekli masaüstü uygulamaları için dağıtım süreci, geleneksel uygulamalara göre bazı ek zorluklar içerir:
•Büyük Model Dosyaları: AI modelleri genellikle büyük boyutlarda olur (MB'dan GB'lara kadar)
•Bağımlılık Karmaşıklığı: TensorFlow, PyTorch, OpenCV gibi kütüphaneler çok sayıda alt bağımlılığa sahiptir
•Platform Uyumluluğu: Farklı işletim sistemlerinde farklı optimizasyonlar gerekebilir
•Performans Gereksinimleri: GPU desteği, CUDA sürücüleri gibi özel gereksinimler
Dağıtım Stratejileri
1.Standalone Executable: Tüm bağımlılıkları içeren tek dosya
2.Installer Package: Kurulum sihirbazı ile dağıtım
3.Portable Application: Kurulum gerektirmeyen taşınabilir uygulama
4.Container-based: Docker gibi konteyner teknolojileri
5.Cloud-based: Hibrit yaklaşım (UI yerel, AI işleme bulutta)
Python Uygulamalarını Paketleme
PyInstaller ile Executable Oluşturma
PyInstaller, Python uygulamalarını standalone executable dosyalara dönüştüren popüler bir araçtır.
Bash
# PyInstaller kurulumu
pip install pyinstaller
Basit Uygulama Örneği
Python
# main.py
import tkinter as tk
from tkinter import messagebox, filedialog
import numpy as np
import cv2
from PIL import Image, ImageTk
import joblib
import os
class AIImageClassifier:
def __init__(self, root):
self.root = root
self.root.title("AI Görüntü Sınıflandırıcı v1.0")
self.root.geometry("600x500")
# Model yolunu belirleme
if getattr(sys, 'frozen', False):
# PyInstaller ile paketlenmiş uygulama
self.base_path = sys._MEIPASS
else:
# Normal Python çalıştırma
self.base_path = os.path.dirname(os.path.abspath(__file__))
self.model_path = os.path.join(self.base_path, 'models', 'classifier.pkl')
self.load_model()
self.setup_ui()
def load_model(self):
try:
self.model = joblib.load(self.model_path)
self.model_loaded = True
except Exception as e:
messagebox.showerror("Model Hatası", f"Model yüklenemedi: {str(e)}")
self.model_loaded = False
def setup_ui(self):
# UI bileşenleri
title_label = tk.Label(self.root, text="AI Görüntü Sınıflandırıcı",
font=("Arial", 16, "bold"))
title_label.pack(pady=10)
# Görüntü seçme butonu
select_btn = tk.Button(self.root, text="Görüntü Seç",
command=self.select_image, font=("Arial", 12))
select_btn.pack(pady=10)
# Görüntü gösterme alanı
self.image_label = tk.Label(self.root, text="Görüntü seçilmedi",
width=40, height=15, bg="lightgray")
self.image_label.pack(pady=10)
# Tahmin butonu
self.predict_btn = tk.Button(self.root, text="Sınıflandır",
command=self.classify_image,
font=("Arial", 12), state="disabled")
self.predict_btn.pack(pady=10)
# Sonuç etiketi
self.result_label = tk.Label(self.root, text="", font=("Arial", 14, "bold"))
self.result_label.pack(pady=10)
# Durum çubuğu
status_frame = tk.Frame(self.root)
status_frame.pack(side=tk.BOTTOM, fill=tk.X)
model_status = "Model Yüklendi" if self.model_loaded else "Model Yüklenemedi"
self.status_label = tk.Label(status_frame, text=f"Durum: {model_status}",
relief=tk.SUNKEN, anchor=tk.W)
self.status_label.pack(side=tk.LEFT, fill=tk.X, expand=True)
self.selected_image_path = None
def select_image(self):
file_path = filedialog.askopenfilename(
title="Görüntü Seç",
filetypes=[("Görüntü dosyaları", "*.png *.jpg *.jpeg *.bmp *.gif")]
)
if file_path:
self.selected_image_path = file_path
self.display_image(file_path)
if self.model_loaded:
self.predict_btn.config(state="normal")
def display_image(self, image_path):
try:
image = Image.open(image_path)
image = image.resize((200, 200), Image.Resampling.LANCZOS)
photo = ImageTk.PhotoImage(image)
self.image_label.config(image=photo, text="")
self.image_label.image = photo
except Exception as e:
messagebox.showerror("Hata", f"Görüntü yüklenemedi: {str(e)}")
def classify_image(self):
if not self.selected_image_path or not self.model_loaded:
return
try:
# Görüntüyü işleme (örnek)
image = cv2.imread(self.selected_image_path)
image = cv2.resize(image, (64, 64))
image_array = image.flatten().reshape(1, -1) / 255.0
# Tahmin yapma
prediction = self.model.predict(image_array)[0]
probability = self.model.predict_proba(image_array).max()
# Sonucu gösterme
result_text = f"Sınıf: {prediction}\nGüven: {probability*100:.1f}%"
self.result_label.config(text=result_text)
except Exception as e:
messagebox.showerror("Hata", f"Sınıflandırma hatası: {str(e)}")
if __name__ == "__main__":
import sys
root = tk.Tk()
app = AIImageClassifier(root)
root.mainloop()
PyInstaller Spec Dosyası
Karmaşık uygulamalar için spec dosyası kullanmak daha iyidir:
Python
# ai_classifier.spec
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
['main.py'],
pathex=[],
binaries=[],
datas=[
('models/*.pkl', 'models'), # Model dosyalarını dahil et
('assets/*.png', 'assets'), # Görsel dosyaları dahil et
('config.json', '.'), # Konfigürasyon dosyası
],
hiddenimports=[
'sklearn.ensemble._forest',
'sklearn.tree._tree',
'sklearn.neighbors._typedefs',
'sklearn.neighbors._quad_tree',
'sklearn.utils._cython_blas',
'cv2',
'numpy',
'PIL',
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[
'matplotlib', # Gereksiz kütüphaneleri hariç tut
'scipy.spatial.cKDTree',
],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='AI_Image_Classifier',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True, # UPX sıkıştırma (isteğe bağlı)
upx_exclude=[],
runtime_tmpdir=None,
console=False, # GUI uygulaması için False
disable_windowed_traceback=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon='assets/app_icon.ico', # Uygulama ikonu
)
Paketleme Komutları
Bash
# Basit paketleme
pyinstaller --onefile --windowed main.py
# Spec dosyası ile paketleme
pyinstaller ai_classifier.spec
# Gelişmiş seçenekler
pyinstaller --onefile \
--windowed \
--icon=app_icon.ico \
--add-data "models;models" \
--add-data "assets;assets" \
--hidden-import=sklearn.ensemble._forest \
--exclude-module=matplotlib \
--name="AI_Image_Classifier" \
main.py
cx_Freeze ile Alternatif Paketleme
Python
# setup.py
from cx_Freeze import setup, Executable
import sys
# Bağımlılıklar
build_exe_options = {
"packages": ["tkinter", "numpy", "cv2", "PIL", "sklearn", "joblib"],
"excludes": ["matplotlib", "scipy"],
"include_files": [
("models/", "models/"),
("assets/", "assets/"),
("config.json", "config.json")
],
"zip_include_packages": ["encodings", "PySide2"],
}
# Platform-specific seçenekler
if sys.platform == "win32":
base = "Win32GUI" # GUI uygulaması için
else:
base = None
setup(
name="AI Image Classifier",
version="1.0",
description="AI-powered image classification tool",
options={"build_exe": build_exe_options},
executables=[
Executable(
"main.py",
base=base,
icon="assets/app_icon.ico",
target_name="AI_Image_Classifier"
)
]
)
Bash
# cx_Freeze ile paketleme
python setup.py build
Platform-Specific Dağıtım
Windows için MSI Installer
Python
# installer_setup.py
from cx_Freeze import setup, Executable
import sys
# MSI seçenekleri
bdist_msi_options = {
"upgrade_code": "{12345678-1234-1234-1234-123456789012}",
"add_to_path": False,
"initial_target_dir": r"[ProgramFilesFolder]\AI Image Classifier",
"install_icon": "assets/app_icon.ico",
}
setup(
name="AI Image Classifier",
version="1.0.0",
description="AI-powered image classification desktop application",
author="Your Name",
author_email="your.email@example.com",
options={
"build_exe": build_exe_options,
"bdist_msi": bdist_msi_options,
},
executables=[
Executable(
"main.py",
base="Win32GUI",
icon="assets/app_icon.ico",
target_name="AI_Image_Classifier",
shortcut_name="AI Image Classifier",
shortcut_dir="DesktopFolder",
)
]
)
Bash
# MSI installer oluşturma
python installer_setup.py bdist_msi
macOS için App Bundle
Python
# setup_mac.py
from setuptools import setup
APP = ['main.py']
DATA_FILES = [
('models', ['models/classifier.pkl']),
('assets', ['assets/app_icon.icns']),
]
OPTIONS = {
'argv_emulation': True,
'iconfile': 'assets/app_icon.icns',
'plist': {
'CFBundleName': 'AI Image Classifier',
'CFBundleDisplayName': 'AI Image Classifier',
'CFBundleGetInfoString': "AI-powered image classification tool",
'CFBundleIdentifier': 'com.yourcompany.aiclassifier',
'CFBundleVersion': '1.0.0',
'CFBundleShortVersionString': '1.0.0',
'NSHumanReadableCopyright': 'Copyright © 2024 Your Company',
'NSHighResolutionCapable': True,
},
'packages': ['tkinter', 'numpy', 'cv2', 'PIL', 'sklearn'],
}
setup(
app=APP,
data_files=DATA_FILES,
options={'py2app': OPTIONS},
setup_requires=['py2app'],
)
Bash
# macOS App Bundle oluşturma
python setup_mac.py py2app
Linux için AppImage
Bash
# AppImage oluşturma scripti
#!/bin/bash
# Gerekli araçları yükleme
wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
chmod +x appimagetool-x86_64.AppImage
# Uygulama dizini oluşturma
mkdir -p AI_Image_Classifier.AppDir/usr/bin
mkdir -p AI_Image_Classifier.AppDir/usr/lib
mkdir -p AI_Image_Classifier.AppDir/usr/share/applications
mkdir -p AI_Image_Classifier.AppDir/usr/share/icons/hicolor/256x256/apps
# Executable'ı kopyalama
cp dist/AI_Image_Classifier AI_Image_Classifier.AppDir/usr/bin/
# Desktop dosyası oluşturma
cat > AI_Image_Classifier.AppDir/AI_Image_Classifier.desktop << EOF
[Desktop Entry]
Type=Application
Name=AI Image Classifier
Exec=AI_Image_Classifier
Icon=ai_classifier
Categories=Graphics;Photography;
EOF
# AppRun scripti
cat > AI_Image_Classifier.AppDir/AppRun << 'EOF'
#!/bin/bash
HERE="$(dirname "$(readlink -f "${0}" )")"
export PATH="${HERE}/usr/bin:${PATH}"
export LD_LIBRARY_PATH="${HERE}/usr/lib:${LD_LIBRARY_PATH}"
exec "${HERE}/usr/bin/AI_Image_Classifier" "$@"
EOF
chmod +x AI_Image_Classifier.AppDir/AppRun
# İkon kopyalama
cp assets/app_icon.png AI_Image_Classifier.AppDir/usr/share/icons/hicolor/256x256/apps/ai_classifier.png
cp assets/app_icon.png AI_Image_Classifier.AppDir/ai_classifier.png
# AppImage oluşturma
./appimagetool-x86_64.AppImage AI_Image_Classifier.AppDir
Docker ile Konteynerleştirme
Plain Text
# Dockerfile
FROM python:3.9-slim
# Sistem bağımlılıklarını yükleme
RUN apt-get update && apt-get install -y \
libgl1-mesa-glx \
libglib2.0-0 \
libsm6 \
libxext6 \
libxrender-dev \
libgomp1 \
libgthread-2.0-0 \
&& rm -rf /var/lib/apt/lists/*
# Çalışma dizini
WORKDIR /app
# Python bağımlılıklarını yükleme
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Uygulama dosyalarını kopyalama
COPY . .
# X11 forwarding için gerekli
ENV DISPLAY=:0
# Uygulamayı çalıştırma
CMD ["python", "main.py"]
YAML
# docker-compose.yml
version: '3.8'
services:
ai-classifier:
build: .
volumes:
- /tmp/.X11-unix:/tmp/.X11-unix:rw
- ./data:/app/data
environment:
- DISPLAY=${DISPLAY}
network_mode: host
stdin_open: true
tty: true
Model Optimizasyonu ve Boyut Azaltma
Model Quantization
Python
# model_optimization.py
import tensorflow as tf
import numpy as np
def quantize_model(model_path, output_path):
"""TensorFlow modelini quantize etme"""
# Modeli yükleme
model = tf.keras.models.load_model(model_path)
# TensorFlow Lite converter
converter = tf.lite.TFLiteConverter.from_keras_model(model)
# Quantization ayarları
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_types = [tf.float16]
# Representative dataset (isteğe bağlı)
def representative_dataset():
for _ in range(100):
yield [np.random.random((1, 224, 224, 3)).astype(np.float32)]
converter.representative_dataset = representative_dataset
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.uint8
converter.inference_output_type = tf.uint8
# Quantized model oluşturma
quantized_model = converter.convert()
# Kaydetme
with open(output_path, 'wb') as f:
f.write(quantized_model)
print(f"Quantized model saved to {output_path}")
# Boyut karşılaştırması
import os
original_size = os.path.getsize(model_path)
quantized_size = os.path.getsize(output_path)
print(f"Original size: {original_size / 1024 / 1024:.2f} MB")
print(f"Quantized size: {quantized_size / 1024 / 1024:.2f} MB")
print(f"Size reduction: {(1 - quantized_size/original_size)*100:.1f}%")
# Kullanım
# quantize_model('models/large_model.h5', 'models/quantized_model.tflite')
Model Pruning
Python
# model_pruning.py
import tensorflow as tf
import tensorflow_model_optimization as tfmot
def prune_model(model, target_sparsity=0.5):
"""Model pruning ile boyut azaltma"""
# Pruning parametreleri
pruning_params = {
'pruning_schedule': tfmot.sparsity.keras.PolynomialDecay(
initial_sparsity=0.0,
final_sparsity=target_sparsity,
begin_step=0,
end_step=1000
)
}
# Modeli prune etme
model_for_pruning = tfmot.sparsity.keras.prune_low_magnitude(
model, **pruning_params
)
# Modeli derleme
model_for_pruning.compile(
optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
return model_for_pruning
def strip_pruning(model):
"""Pruning wrapper'ını kaldırma"""
return tfmot.sparsity.keras.strip_pruning(model)
Güvenlik ve Lisanslama
Kod Obfuscation
Python
# obfuscation_example.py
import base64
import zlib
def obfuscate_code(source_code):
"""Basit kod gizleme"""
# Kodu sıkıştır ve base64 encode et
compressed = zlib.compress(source_code.encode())
encoded = base64.b64encode(compressed).decode()
# Obfuscated kod şablonu
obfuscated = f"""
import base64
import zlib
exec(zlib.decompress(base64.b64decode('{encoded}')).decode())
"""
return obfuscated
# Kullanım
# with open('sensitive_module.py', 'r') as f:
# source = f.read()
#
# obfuscated = obfuscate_code(source)
# with open('obfuscated_module.py', 'w') as f:
# f.write(obfuscated)
Lisans Kontrolü
Python
# license_manager.py
import hashlib
import datetime
import json
from cryptography.fernet import Fernet
class LicenseManager:
def __init__(self, key=None):
if key is None:
key = Fernet.generate_key()
self.cipher = Fernet(key)
self.key = key
def generate_license(self, user_info, expiry_date, features=None):
"""Lisans oluşturma"""
license_data = {
'user': user_info,
'expiry': expiry_date.isoformat(),
'features': features or [],
'generated': datetime.datetime.now().isoformat()
}
# JSON'u şifrele
json_data = json.dumps(license_data).encode()
encrypted = self.cipher.encrypt(json_data)
return encrypted.hex()
def validate_license(self, license_key):
"""Lisans doğrulama"""
try:
# Hex'den bytes'a çevir
encrypted_data = bytes.fromhex(license_key)
# Şifreyi çöz
decrypted = self.cipher.decrypt(encrypted_data)
license_data = json.loads(decrypted.decode())
# Tarih kontrolü
expiry_date = datetime.datetime.fromisoformat(license_data['expiry'])
if datetime.datetime.now() > expiry_date:
return False, "License expired"
return True, license_data
except Exception as e:
return False, f"Invalid license: {str(e)}"
def check_feature(self, license_key, feature):
"""Özellik kontrolü"""
valid, data = self.validate_license(license_key)
if not valid:
return False
if isinstance(data, dict):
return feature in data.get('features', [])
return False
# Kullanım örneği
def license_protected_app():
license_manager = LicenseManager()
# Uygulama başlangıcında lisans kontrolü
license_file = "license.key"
try:
with open(license_file, 'r') as f:
license_key = f.read().strip()
valid, info = license_manager.validate_license(license_key)
if not valid:
print(f"License error: {info}")
return False
print(f"License valid for: {info['user']}")
return True
except FileNotFoundError:
print("License file not found!")
return False
Otomatik Güncelleme Sistemi
Python
# auto_updater.py
import requests
import json
import os
import subprocess
import tempfile
from packaging import version
class AutoUpdater:
def __init__(self, current_version, update_url):
self.current_version = current_version
self.update_url = update_url
def check_for_updates(self):
"""Güncelleme kontrolü"""
try:
response = requests.get(f"{self.update_url}/version.json", timeout=10)
response.raise_for_status()
update_info = response.json()
latest_version = update_info['version']
if version.parse(latest_version) > version.parse(self.current_version):
return True, update_info
else:
return False, None
except Exception as e:
print(f"Update check failed: {e}")
return False, None
def download_update(self, update_info):
"""Güncellemeyi indirme"""
download_url = update_info['download_url']
try:
response = requests.get(download_url, stream=True, timeout=30)
response.raise_for_status()
# Geçici dosyaya indirme
with tempfile.NamedTemporaryFile(delete=False, suffix='.exe') as tmp_file:
for chunk in response.iter_content(chunk_size=8192):
tmp_file.write(chunk)
return tmp_file.name
except Exception as e:
print(f"Download failed: {e}")
return None
def install_update(self, installer_path):
"""Güncellemeyi yükleme"""
try:
# Installer'ı çalıştır
subprocess.Popen([installer_path, '/S']) # Silent install
# Mevcut uygulamayı kapat
os._exit(0)
except Exception as e:
print(f"Installation failed: {e}")
return False
def auto_update_check(self):
"""Otomatik güncelleme kontrolü ve kurulumu"""
has_update, update_info = self.check_for_updates()
if has_update:
print(f"New version available: {update_info['version']}")
# Kullanıcıya sor (GUI'de dialog göster)
user_choice = input("Do you want to update now? (y/n): ")
if user_choice.lower() == 'y':
installer_path = self.download_update(update_info)
if installer_path:
self.install_update(installer_path)
return True
return False
# Uygulama başlangıcında kullanım
def main():
updater = AutoUpdater("1.0.0", "https://your-server.com/updates" )
# Güncelleme kontrolü (arka planda)
import threading
update_thread = threading.Thread(target=updater.auto_update_check)
update_thread.daemon = True
update_thread.start()
# Ana uygulama kodunuz buraya gelir
# ...
Dağıtım Checklist
Ön Dağıtım Kontrolleri
Python
# deployment_checklist.py
import os
import sys
import subprocess
import json
class DeploymentChecker:
def __init__(self):
self.checks = []
self.errors = []
self.warnings = []
def check_dependencies(self):
"""Bağımlılık kontrolü"""
required_packages = [
'numpy', 'opencv-python', 'scikit-learn',
'tensorflow', 'pillow', 'joblib'
]
missing_packages = []
for package in required_packages:
try:
__import__(package.replace('-', '_'))
except ImportError:
missing_packages.append(package)
if missing_packages:
self.errors.append(f"Missing packages: {missing_packages}")
else:
self.checks.append("✓ All dependencies available")
def check_model_files(self):
"""Model dosyası kontrolü"""
model_paths = [
'models/classifier.pkl',
'models/preprocessor.pkl'
]
missing_models = []
for path in model_paths:
if not os.path.exists(path):
missing_models.append(path)
if missing_models:
self.errors.append(f"Missing model files: {missing_models}")
else:
self.checks.append("✓ All model files present")
def check_file_sizes(self):
"""Dosya boyutu kontrolü"""
large_files = []
for root, dirs, files in os.walk('.'):
for file in files:
file_path = os.path.join(root, file)
size_mb = os.path.getsize(file_path) / (1024 * 1024)
if size_mb > 100: # 100MB'dan büyük dosyalar
large_files.append((file_path, f"{size_mb:.1f}MB"))
if large_files:
self.warnings.append(f"Large files detected: {large_files}")
else:
self.checks.append("✓ No unusually large files")
def check_permissions(self):
"""İzin kontrolü"""
critical_files = ['main.py', 'models/', 'assets/']
permission_issues = []
for item in critical_files:
if os.path.exists(item):
if not os.access(item, os.R_OK):
permission_issues.append(f"No read access: {item}")
else:
permission_issues.append(f"File not found: {item}")
if permission_issues:
self.errors.append(f"Permission issues: {permission_issues}")
else:
self.checks.append("✓ File permissions OK")
def run_all_checks(self):
"""Tüm kontrolleri çalıştır"""
print("Running deployment checks...\n")
self.check_dependencies()
self.check_model_files()
self.check_file_sizes()
self.check_permissions()
# Sonuçları göster
print("✅ PASSED CHECKS:")
for check in self.checks:
print(f" {check}")
if self.warnings:
print("\n⚠️ WARNINGS:")
for warning in self.warnings:
print(f" {warning}")
if self.errors:
print("\n❌ ERRORS:")
for error in self.errors:
print(f" {error}")
print("\n🚫 Deployment not recommended!")
return False
else:
print("\n✅ Ready for deployment!")
return True
# Kullanım
if __name__ == "__main__":
checker = DeploymentChecker()
ready = checker.run_all_checks()
sys.exit(0 if ready else 1)
Sonuç
Bu derste, yapay zeka destekli masaüstü uygulamalarınızı son kullanıcılara nasıl dağıtacağınızı öğrendiniz. Dağıtım süreci, uygulamanızın başarısı için kritik öneme sahiptir. Doğru paketleme, optimizasyon ve güvenlik önlemleri alarak, kullanıcılarınıza profesyonel bir deneyim sunabilirsiniz.
Önemli noktalar:
•Model boyutlarını optimize edin
•Platform-specific paketleme araçlarını kullanın
•Güvenlik ve lisanslama konularını ihmal etmeyin
•Otomatik güncelleme sistemi kurun
•Dağıtım öncesi kapsamlı testler yapın
Bu eğitim serisini tamamladığınızda, yapay zeka teknolojilerini masaüstü uygulamalarına entegre etme konusunda sağlam bir temel kazanmış olacaksınız.