OsBaran commited on
Commit
e8bcd6a
·
verified ·
1 Parent(s): 6612b8f

Upload 26 files

Browse files
app_selfies_singlev8.py ADDED
@@ -0,0 +1,2260 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # =========================================================================
2
+ # I. KURULUM VE KÜTÜPHANELER
3
+ # =========================================================================
4
+ import google.generativeai as genai
5
+ import streamlit as st
6
+ import numpy as np
7
+ import pandas as pd
8
+ import joblib
9
+ import random
10
+ import operator
11
+ import time
12
+ import math
13
+ from stmol import showmol
14
+ import py3Dmol
15
+ import pubchempy as pcp
16
+ # Optimizasyon için DEAP kütüphanesi
17
+ import deap.base as base
18
+ import deap.creator as creator
19
+ import deap.tools as tools
20
+ from deap import algorithms
21
+ import lightgbm as lgbm
22
+ # Kimya kütüphaneleri
23
+ from rdkit import Chem
24
+ from rdkit.Chem import AllChem
25
+ from rdkit import RDLogger
26
+ import selfies as sf
27
+ from datasets import load_dataset
28
+ import rdkit.Chem.rdChemReactions as rdChemReactions
29
+ # import stmol as showmol # 3D görselleştirme kütüphanesi (varsa)
30
+
31
+ RDLogger.DisableLog('rdApp.*')
32
+ from rdkit.Chem import Draw
33
+ from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
34
+ import matplotlib.pyplot as plt
35
+ # --- YEREL RETROSENTEZ MODELİ ENTEGRASYONU ---
36
+
37
+ from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
38
+
39
+ # --- MODELİ ÖNBELLEĞE AL (Sadece 1 kere yüklenir) ---
40
+ @st.cache_resource
41
+ def load_my_trained_model():
42
+ model_path = "./PolimerX_Model"
43
+ try:
44
+ tokenizer = AutoTokenizer.from_pretrained(model_path)
45
+ model = AutoModelForSeq2SeqLM.from_pretrained(model_path)
46
+ return tokenizer, model
47
+ except Exception as e:
48
+ st.error(f"Model yüklenemedi: {e}")
49
+ return None, None
50
+
51
+ def predict_monomers_local(polymer_smiles):
52
+ """
53
+ Önce eğitilmiş T5 modelini kullanır.
54
+ Eğer sonuç başarısızsa kural tabanlı motoru devreye sokar.
55
+ """
56
+ # 1. MODEL TAHMİNİ
57
+ tokenizer, model = load_my_trained_model()
58
+ ai_prediction = ""
59
+
60
+ if model:
61
+ try:
62
+ # Eğitimde kullandığımız "retrosynthesis: " ön ekini unutmuyoruz!
63
+ input_text = "retrosynthesis: " + polymer_smiles
64
+ inputs = tokenizer(input_text, return_tensors="pt")
65
+
66
+ # Tahmin üret
67
+ outputs = model.generate(
68
+ inputs["input_ids"],
69
+ max_length=128,
70
+ num_beams=5, # En iyi 5 yolu ara
71
+ early_stopping=True
72
+ )
73
+ ai_prediction = tokenizer.decode(outputs[0], skip_special_tokens=True)
74
+ except:
75
+ ai_prediction = ""
76
+
77
+ # 2. SONUÇ KONTROLÜ VE HİBRİT KARAR
78
+ # Model mantıklı bir şey (örneğin nokta ile ayrılmış iki parça) döndürdü mü?
79
+ if ai_prediction and " . " in ai_prediction:
80
+ return f"{ai_prediction} (Yerel AI Modeli)"
81
+
82
+ # Model başarısızsa veya emin değilse KURAL MOTORUNU çağır
83
+ else:
84
+ rules = decompose_polymer(polymer_smiles) # Mevcut fonksiyonun
85
+ if rules:
86
+ monomers = rules[0]['monomers']
87
+ return f"{' . '.join(monomers)} (Kural Tabanlı - Yedek)"
88
+ else:
89
+ # Model bir şey buldu ama nokta yoksa yine de gösterelim (belki tek monomerdir)
90
+ if ai_prediction:
91
+ return f"{ai_prediction} (AI Modeli - Tek Parça)"
92
+ return "Ayrıştırılamadı"
93
+ # --- YAYGIN ÇÖZÜCÜLER REFERANS LİSTESİ ---
94
+ COMMON_SOLVENTS = {
95
+ "n-Heksan (Apolar)": 7.3,
96
+ "Dietil Eter": 7.4,
97
+ "Toluen (Aromatik)": 8.9,
98
+ "Etil Asetat": 9.1,
99
+ "Kloroform": 9.3,
100
+ "Aseton (Polar Aprotik)": 9.9,
101
+ "Diklorometan (DCM)": 9.7,
102
+ "THF (Tetrahidrofuran)": 9.1,
103
+ "Etanol (Alkol)": 12.7,
104
+ "Metanol": 14.5,
105
+ "Su (Çok Polar)": 23.4
106
+ }
107
+ def get_soluble_solvents(pred_val):
108
+ """Tahmin edilen Hildebrand değerine göre uygun çözücüleri bulur."""
109
+ soluble_list = []
110
+ swelling_list = [] # Kısmi çözünme / Şişme
111
+
112
+ for solvent, s_val in COMMON_SOLVENTS.items():
113
+ diff = abs(pred_val - s_val)
114
+
115
+ if diff <= 1.8: # İyi çözücü
116
+ soluble_list.append(solvent)
117
+ elif diff <= 2.5: # Sınırda (Isıtarak çözünebilir veya şişer)
118
+ swelling_list.append(solvent)
119
+
120
+ return soluble_list, swelling_list
121
+ def draw_2d_molecule(smiles):
122
+ """SMILES kodundan yüksek kaliteli 2D resim oluşturur."""
123
+ try:
124
+ mol = Chem.MolFromSmiles(smiles)
125
+ if mol:
126
+ # Görüntü kalitesini artır
127
+ dopts = Draw.MolDrawOptions()
128
+ dopts.addAtomIndices = False
129
+ dopts.bondLineWidth = 2
130
+ return Draw.MolToImage(mol, size=(500, 400), options=dopts)
131
+ except:
132
+ return None
133
+ def inject_custom_css():
134
+ st.markdown("""
135
+ <style>
136
+ /* Ana Başlık Stili */
137
+ .main-title {
138
+ font-size: 3rem;
139
+ color: #4A90E2;
140
+ font-weight: 700;
141
+ text-align: center;
142
+ margin-bottom: 1rem;
143
+ }
144
+ /* Alt Başlık */
145
+ .sub-title {
146
+ font-size: 1.2rem;
147
+ color: #666;
148
+ text-align: center;
149
+ margin-bottom: 2rem;
150
+ }
151
+ /* Kart Tasarımı (Sonuçlar için) */
152
+ .metric-card {
153
+ background-color: #f9f9f9;
154
+ border-left: 5px solid #4A90E2;
155
+ padding: 15px;
156
+ border-radius: 8px;
157
+ box-shadow: 2px 2px 5px rgba(0,0,0,0.1);
158
+ margin-bottom: 10px;
159
+ }
160
+ /* Dark Mode Uyumu için Kart Rengi */
161
+ @media (prefers-color-scheme: dark) {
162
+ .metric-card {
163
+ background-color: #262730;
164
+ border-left: 5px solid #4A90E2;
165
+ color: white;
166
+ }
167
+ }
168
+ </style>
169
+ """, unsafe_allow_html=True)
170
+
171
+ # Uygulamanın en başında çağırın:
172
+ inject_custom_css()
173
+ # --- SABİTLER ---
174
+ N_BITS = 2048 # Morgan Fingerprint boyutu
175
+ @st.cache_data
176
+ def get_initial_population():
177
+ """Verisetini sadece bir kez indirir ve önbelleğe alır."""
178
+ repo_id = "OsBaran/Polimer-Ozellik-Tahmini"
179
+ tg_data = load_dataset(repo_id, split="Tg")
180
+ df = tg_data.to_pandas()
181
+ col_name = 'p_smiles' if 'p_smiles' in df.columns else 'smiles'
182
+ # Sadece geçerli SELFIES'leri filtrele ve listeye çevir
183
+ raw_smiles = df[col_name].tolist()
184
+ valid_selfies = []
185
+ for s in raw_smiles:
186
+ sf_str = smiles_to_selfies_safe(s)
187
+ if sf_str:
188
+ valid_selfies.append(sf_str)
189
+ return valid_selfies, raw_smiles # İkisini de döndür
190
+ # --- MODEL YÜKLEME ---
191
+ @st.cache_resource
192
+ def load_critic_models():
193
+ """Tüm Eleştirmen (Critic) modellerini yükler."""
194
+ models = {}
195
+ try:
196
+ models['Tg'] = joblib.load('xgb_tg.joblib')
197
+ models['Td'] = joblib.load('xgb_td.joblib')
198
+ models['EPS'] = joblib.load('rf_eps.joblib')
199
+ # DİĞER MODELLERİNİZİ BURAYA EKLEYİN
200
+ models['Tm'] = joblib.load('xgb_tm.joblib')
201
+ models['BandgapBulk'] = joblib.load('xgb_band gap bulk.joblib')
202
+ models['BandgapChain'] = joblib.load('xgb_band gap chain.joblib')
203
+ models['BandgapCrystal'] = joblib.load('xgb_bandgap-crystal.joblib')
204
+ models['GasPerma'] = joblib.load('lgbm_gas_pipeline.joblib')
205
+ models['Refractive'] = joblib.load('rf_refractive_index.joblib')
206
+
207
+ models['LOI'] = joblib.load('xgb_loi.joblib') # Yanıcılık
208
+ models['Solubility'] = joblib.load('xgb_solubility.joblib') # Çözünürlük
209
+ models['ThermalCond'] = joblib.load('xgb_thermal_cond.joblib') # Isıl İletkenlik
210
+ models['CTE'] = joblib.load('xgb_cte.joblib')
211
+
212
+ return models
213
+ except Exception as e:
214
+ st.error(f"⚠️ Model Yükleme Hatası! Lütfen 'tg_model.joblib', 'td_model.joblib' ve 'eps_model.joblib' dosyalarının mevcut olduğundan emin olun. Hata: {e}")
215
+ return None
216
+
217
+ def run_ga_silent(models, generations, targets, active_props, initial_pop, ranges_dict):
218
+ """
219
+ GA'yı grafik çizmeden (sessizce) çalıştırır. Çoklu testler için optimize edilmiştir.
220
+ """
221
+ # DEAP Kurulumu (Mevcut kodunuzdakiyle aynı)
222
+ toolbox = base.Toolbox()
223
+ toolbox.register("attr_selfies", random.choice, initial_pop)
224
+ toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_selfies, n=1)
225
+ toolbox.register("population", tools.initRepeat, list, toolbox.individual)
226
+ toolbox.register("evaluate", evaluate_individual_optimized, models=models, targets=targets, active_props=active_props, ranges=ranges_dict)
227
+ toolbox.register("mate", cxSelfies)
228
+ toolbox.register("select", tools.selTournament, tournsize=7) # Turnuva boyutu 7 (Önerilen)
229
+
230
+ pop_size = 100
231
+ pop = toolbox.population(n=pop_size)
232
+
233
+ # Sadece en iyilerin geçmişini tutacağız
234
+ best_fitness_history = []
235
+
236
+ # Parametreler (Optimize ettiğimiz değerler)
237
+ cxpb, mutpb, extendpb, newpb, chempb = 0.8, 0.05, 0.05, 0.01, 0.05
238
+
239
+ # --- HIZLI DÖNGÜ ---
240
+ for gen in range(generations):
241
+ # Seçilim & Klonlama
242
+ offspring = toolbox.select(pop, pop_size)
243
+ offspring = list(map(toolbox.clone, offspring))
244
+
245
+ # Çaprazlama
246
+ for child1, child2 in zip(offspring[::2], offspring[1::2]):
247
+ if random.random() < cxpb:
248
+ toolbox.mate(child1, child2)
249
+ del child1.fitness.values, child2.fitness.values
250
+
251
+ # Mutasyon
252
+ for i in range(len(offspring)):
253
+ if not offspring[i].fitness.valid: pass
254
+ offspring[i] = generate_offspring(offspring[i], initial_pop, mutpb=mutpb, extendpb=extendpb, newpb=newpb, chempb=chempb)
255
+ del offspring[i].fitness.values
256
+
257
+ # Değerlendirme
258
+ invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
259
+ fitnesses = map(toolbox.evaluate, invalid_ind)
260
+ for ind, fit in zip(invalid_ind, fitnesses):
261
+ ind.fitness.values = fit
262
+
263
+ pop = offspring
264
+
265
+ # En iyiyi kaydet
266
+ fits = [ind.fitness.values[0] for ind in pop]
267
+ best_fitness_history.append(min(fits))
268
+
269
+ return best_fitness_history
270
+ # --- YARDIMCI KİMYA FONKSİYONLARI (Değişmedi) --
271
+ def run_mass_random_test(models, generations, initial_pop, ranges_dict, num_trials=100):
272
+ """
273
+ Rastgele hedeflerle 100 kez stres testi yapar.
274
+ """
275
+ results = []
276
+ all_props_list = list(ranges_dict.keys())
277
+
278
+ # İlerleme Göstergeleri
279
+ progress_bar = st.progress(0)
280
+ status_text = st.empty()
281
+
282
+ for i in range(num_trials):
283
+ # 1. RASTGELE SENARYO OLUŞTURMA
284
+ # Kaç özellik optimize edilecek? (2 ile 5 arası rastgele)
285
+ n_active = random.randint(2, 5)
286
+ # Hangi özellikler olacak?
287
+ active_props = random.sample(all_props_list, n_active)
288
+
289
+ # Hedefleri belirle (Rastgele)
290
+ current_targets = {}
291
+ target_descriptions = []
292
+ for prop in active_props:
293
+ r = ranges_dict[prop]
294
+ # Min ve Max arasında rastgele bir değer seç
295
+ val = random.uniform(r['min'], r['max'])
296
+
297
+ # Bazı değerleri tam sayıya yuvarla (Sıcaklıklar gibi)
298
+ if r.get('is_int', False) or prop in ['Tg', 'Td', 'Tm', 'LOI']:
299
+ val = round(val, 0)
300
+ else:
301
+ val = round(val, 2)
302
+
303
+ current_targets[prop] = val
304
+ target_descriptions.append(f"{prop}={val}")
305
+
306
+ # 2. GA'YI ÇALIŞTIR (Sessiz Modda)
307
+ # run_ga_silent fonksiyonunu önceki adımdan aldığınızı varsayıyorum
308
+ history = run_ga_silent(models, generations, current_targets, active_props, initial_pop, ranges_dict)
309
+
310
+ # 3. SONUCU KAYDET
311
+ final_score = history[-1] # En son jenerasyonun en iyi skoru
312
+
313
+ results.append({
314
+ "Deneme No": i + 1,
315
+ "Hedef Sayısı": n_active,
316
+ "Hedefler": ", ".join(target_descriptions),
317
+ "Final Hata Skoru": final_score
318
+ })
319
+
320
+ # İlerlemeyi Güncelle
321
+ progress_bar.progress((i + 1) / num_trials)
322
+ status_text.text(f"Test {i+1}/{num_trials} | Son Hata: {final_score:.4f} | Hedefler: {', '.join(target_descriptions)[:50]}...")
323
+
324
+ status_text.success(f"{num_trials} Farklı Senaryo Testi Tamamlandı!")
325
+ return pd.DataFrame(results)
326
+ def smiles_to_selfies_safe(smiles):
327
+ if not smiles: return None
328
+ clean_smi = smiles.replace('*', '[H]').replace('(*)', '[H]').replace('[*]', '[H]')
329
+ try:
330
+ selfies_string = sf.encoder(clean_smi)
331
+ return selfies_string.replace('[H]', '[*]')
332
+ except:
333
+ return None
334
+
335
+ def selfies_to_smiles_safe(selfes_string):
336
+ if not selfes_string: return None
337
+ try:
338
+ temp_selfies = selfes_string.replace('[*]', '[H]')
339
+ smiles = sf.decoder(temp_selfies)
340
+ return smiles.replace('[H]', '*')
341
+ except:
342
+ return None
343
+
344
+ def get_morgan_fp(p_smiles):
345
+ smi_clean = str(p_smiles).replace('*', '[H]').replace('(*)', '[H]').replace('[*]', '[H]')
346
+ mol = Chem.MolFromSmiles(smi_clean)
347
+ if mol is None: return None
348
+ fp = AllChem.GetMorganFingerprintAsBitVect(mol, 3, N_BITS)
349
+ return np.array([fp])
350
+ # --- MEVCUT IMPORTLARIN ALTINA EKLE ---
351
+ from rdkit.Chem import Descriptors
352
+
353
+ # --- YENİ ÖZELLİK FONKSİYONU ---
354
+ def get_gas_features_combined(smiles):
355
+ """
356
+ Gaz geçirgenliği LGBM modeli için hem Morgan FP hem de
357
+ Fiziksel Deskriptörleri birleştirir.
358
+ """
359
+ try:
360
+ mol = Chem.MolFromSmiles(smiles.replace('*', '[H]'))
361
+ if mol is None: return None
362
+
363
+ # 1. Morgan Fingerprint (2048 bit)
364
+ fp = np.array(AllChem.GetMorganFingerprintAsBitVect(mol, 3, nBits=2048))
365
+
366
+ # 2. Fiziksel Deskriptörler
367
+ desc = np.array([
368
+ Descriptors.MolWt(mol),
369
+ Descriptors.MolLogP(mol),
370
+ Descriptors.TPSA(mol),
371
+ Descriptors.NumRotatableBonds(mol),
372
+ Descriptors.FractionCSP3(mol),
373
+ Descriptors.HallKierAlpha(mol)
374
+ ])
375
+
376
+ # İkisini birleştir
377
+ return np.concatenate((fp, desc)).reshape(1, -1)
378
+ except:
379
+ return None
380
+ def cxSelfies(ind1, ind2):
381
+ t1 = list(sf.split_selfies(ind1[0]))
382
+ t2 = list(sf.split_selfies(ind2[0]))
383
+ min_len = min(len(t1), len(t2))
384
+ if min_len < 2: return ind1, ind2
385
+
386
+ # Segmentleri belirle
387
+ split1 = random.randint(1, min_len-1)
388
+ split2 = random.randint(1, min_len-1)
389
+
390
+ new1 = t1[:split1] + t2[split2:]
391
+ new2 = t2[:split2] + t1[split1:]
392
+
393
+ # Valid bireyleri seç
394
+ new1_str = "".join(new1)
395
+ new2_str = "".join(new2)
396
+
397
+ if is_valid_polymer(new1_str):
398
+ ind1[0] = new1_str
399
+ if is_valid_polymer(new2_str):
400
+ ind2[0] = new2_str
401
+ return ind1, ind2
402
+
403
+ def mutSelfies(individual):
404
+ # Mutasyon fonksiyonu (Değişmedi)
405
+ tokens = list(sf.split_selfies(individual[0]))
406
+ if not tokens: return individual,
407
+ if random.random() < 0.6 and len(tokens) > 1:
408
+ idx = random.randint(0, len(tokens) - 1)
409
+ del tokens[idx]
410
+ if random.random() < 0.4:
411
+ idx = random.randint(0, len(tokens))
412
+ new_token = random.choice(['[C]', '[N]', '[O]', '[F]', '[Cl]', '[S]', '[*]'])
413
+ tokens.insert(idx, new_token)
414
+ individual[0] = "".join(tokens)
415
+ return individual,
416
+
417
+ # =========================================================================
418
+ # II. DİNAMİK DEĞERLENDİRME ÇEKİRDEĞİ (DYNAMIC EVALUATE)
419
+ # =========================================================================
420
+ # II. DİNAMİK DEĞERLENDİRME ÇEKİRDEĞİ kısmına ekleyin
421
+
422
+ # Global önbellek sözlüğü (Uygulama yeniden başlayana kadar tutulur)
423
+ # Key: SELFIES string, Value: (Fitness Score,)
424
+ FITNESS_CACHE = {}
425
+
426
+ def evaluate_individual_optimized(individual, models, targets, active_props, ranges):
427
+ s_selfies = individual[0]
428
+
429
+ # Önbellek Kontrolü
430
+ if s_selfies in FITNESS_CACHE:
431
+ return FITNESS_CACHE[s_selfies]
432
+
433
+ s_smiles = selfies_to_smiles_safe(s_selfies)
434
+ if s_smiles is None: return (1000.0,)
435
+
436
+ # Standart Fingerprint (Diğer modeller için)
437
+ fp = get_morgan_fp(s_smiles)
438
+
439
+ # Gas Model Özellikleri (Sadece GasPerma aktifse hesapla)
440
+ gas_features = None
441
+ if 'GasPerma' in active_props:
442
+ gas_features = get_gas_features_combined(s_smiles)
443
+
444
+ if fp is None: return (1000.0,)
445
+
446
+ preds = {}
447
+
448
+ # --- TAHMİN DÖNGÜSÜ ---
449
+ for prop in active_props:
450
+ if prop in models:
451
+ # ÖZEL DURUM: GasPerma modeli için özel özellikleri kullan
452
+ if prop == 'GasPerma':
453
+ if gas_features is not None:
454
+ # Model log10 tahmini yapıyor, bunu gerçek değere çeviriyoruz (10^x)
455
+ log_pred = models[prop].predict(gas_features)[0]
456
+ preds[prop] = 10 ** log_pred
457
+ else:
458
+ preds[prop] = 0.0 # Hata durumunda
459
+
460
+ # DİĞERLERİ: Standart Fingerprint kullanır
461
+ else:
462
+ preds[prop] = models[prop].predict(fp)[0]
463
+
464
+ # --- HATA HESAPLAMA ---
465
+ total_error = 0.0
466
+ if not active_props: return (1000.0,)
467
+
468
+ for prop in active_props:
469
+ if prop in preds:
470
+ norm_error = abs(preds[prop] - targets[prop]) / (ranges[prop]['max'] - ranges[prop]['min'])
471
+ total_error += np.exp(norm_error * 10) - 1
472
+
473
+ # ... (Geri kalan SA Score ve return kısmı aynı kalacak) ...
474
+ sa_score = get_sa_score_local(s_smiles)
475
+ total_error += sa_score * 2.0
476
+
477
+ result = (total_error,)
478
+ FITNESS_CACHE[s_selfies] = result
479
+ return result
480
+ def run_random_benchmark(models, targets, active_props, initial_pop, ranges_dict, total_budget, batch_size=100):
481
+ """
482
+ GA ile adil kıyaslama için Rastgele Arama (Random Search) yapar.
483
+ total_budget: Toplam değerlendirme sayısı (GA'daki pop_size * generations)
484
+ batch_size: Grafik çizimi için her kaç adımda bir kayıt alınacağı (GA'daki pop_size kadar olmalı)
485
+ """
486
+ history_random = []
487
+ best_so_far = float('inf')
488
+
489
+ # İlerleme çubuğu (kullanıcı beklerken sıkılmasın)
490
+ progress_text = st.empty()
491
+ bar = st.progress(0)
492
+
493
+ for i in range(0, total_budget, batch_size):
494
+ # Batch (Grup) halindeki rastgele bireyler
495
+ # initial_pop listesinden rastgele seç
496
+ candidates = random.sample(initial_pop, batch_size)
497
+
498
+ scores = []
499
+ for ind_selfies in candidates:
500
+ # Mevcut evaluate fonksiyonunu kullanıyoruz (Adil olması için)
501
+ # individual formatı liste olduğu için [ind_selfies] şeklinde veriyoruz
502
+ fit = evaluate_individual_optimized([ind_selfies], models, targets, active_props, ranges_dict)
503
+
504
+ # Ceza puanı alanları (1000) filtreleyebiliriz veya olduğu gibi alabiliriz
505
+ # Random search genelde çok hata yapar, olduğu gibi alalım.
506
+ scores.append(fit[0])
507
+
508
+ # Bu batch'teki en iyiyi bul
509
+ current_batch_best = min(scores)
510
+
511
+ # Genel en iyiyi güncelle
512
+ if current_batch_best < best_so_far:
513
+ best_so_far = current_batch_best
514
+
515
+ history_random.append(best_so_far)
516
+
517
+ # İlerlemeyi güncelle
518
+ progress = (i + batch_size) / total_budget
519
+ if progress > 1.0: progress = 1.0
520
+ bar.progress(progress)
521
+ progress_text.text(f"Rastgele Arama: {i}/{total_budget} tamamlandı. En iyi skor: {best_so_far:.4f}")
522
+
523
+ bar.empty()
524
+ progress_text.empty()
525
+ return history_random
526
+
527
+ def evaluate_individual_single_obj(individual, models, targets, active_props):
528
+
529
+ """
530
+
531
+ Seçilen hedeflere (active_props) olan toplam mesafeye (hata) göre değerlendirir.
532
+
533
+ """
534
+
535
+ s_selfies = individual[0]
536
+
537
+ s_smiles = selfies_to_smiles_safe(s_selfies)
538
+
539
+
540
+
541
+ if s_smiles is None:
542
+
543
+ return (1000.0,)
544
+
545
+
546
+
547
+ fp = get_morgan_fp(s_smiles)
548
+
549
+ if fp is None:
550
+
551
+ return (1000.0,)
552
+
553
+
554
+
555
+ # 1. Tahminleri Al
556
+
557
+ preds = {}
558
+
559
+ for prop in active_props:
560
+
561
+ if prop in models:
562
+
563
+ preds[prop] = models[prop].predict(fp)[0]
564
+
565
+
566
+
567
+ # 2. Toplam Hatayı Hesapla
568
+
569
+ total_error = 0.0
570
+
571
+
572
+
573
+ if not active_props:
574
+
575
+ # Hiçbir hedef seçilmezse ceza
576
+
577
+ return (1000.0,)
578
+
579
+
580
+
581
+ for prop in active_props:
582
+
583
+ # Hata = |Tahmin - Hedef|
584
+
585
+ if prop in preds:
586
+
587
+ norm_error = abs(preds[prop] - targets[prop]) / (ranges[prop]['max'] - ranges[prop]['min'])
588
+
589
+ total_error += np.exp(norm_error * 10) - 1 # Küçük farklar neredeyse lineer, büyük farklar çok ağır
590
+
591
+
592
+
593
+ # Seçilen hiçbir özellik hesaplanamazsa büyük ceza
594
+
595
+ if total_error == 0.0 and len(active_props) > 0:
596
+
597
+ return (1000.0,)
598
+
599
+ total_error += get_sa_score_local(s_smiles) / 10.0 # SA Score ekle
600
+
601
+
602
+ return (total_error,)
603
+
604
+ # =========================================================================
605
+ # III. ANA GENETİK ALGORİTMA AKIŞI
606
+ # =========================================================================
607
+
608
+ # DEAP Yapısını Tanımlama (Minimizasyon için)
609
+ if "FitnessMin" not in creator.__dict__:
610
+ creator.create("FitnessMin", base.Fitness, weights=(-1.0,)) # Minimizasyon için
611
+ creator.create("Individual", list, fitness=creator.FitnessMin)
612
+
613
+ # =========================
614
+ # 1. Sentezlenebilirlik Kontrolü
615
+ # =========================
616
+ def is_valid_polymer(selfies_str):
617
+ """
618
+ Hem kimyasal geçerliliği hem de polimer olma şartını (bağlantı noktaları) kontrol eder.
619
+ """
620
+ # 1. SELFIES -> SMILES dönüşümü
621
+ smiles = selfies_to_smiles_safe(selfies_str)
622
+ if smiles is None:
623
+ return False
624
+
625
+ # ==========================================================
626
+ # KONTROL 1: Bağlantı Noktası (Star Atom) Kontrolü
627
+ # ==========================================================
628
+ # Bir polimerin tekrar eden birim (monomer) olması için
629
+ # en az 2 ucunun açık olması gerekir (* işareti).
630
+ # Lineer polimerler için genellikle tam 2 adet istenir.
631
+ # Ağ yapılı (cross-linked) polimerler için >2 olabilir.
632
+
633
+ star_count = smiles.count('*')
634
+ if star_count < 2:
635
+ return False # Zincir kopmuş, bu artık bir polimer değil.
636
+
637
+ # ==========================================================
638
+ # KONTROL 2: Çok Küçük Moleküllerin Engellenmesi
639
+ # ==========================================================
640
+ # GA bazen "*C*" gibi çok anlamsız küçük şeyler üretebilir.
641
+ # Yıldızlar hariç atom sayısına bakabiliriz.
642
+
643
+ clean_smi = smiles.replace('*', '[H]')
644
+ mol = Chem.MolFromSmiles(clean_smi)
645
+
646
+ if mol is None:
647
+ return False # Kimyasal olarak bozuk
648
+
649
+ # Yıldızlar (Hidrojen oldu) hariç ağır atom sayısı (C, O, N vs.) en az 4 olsun
650
+ if mol.GetNumHeavyAtoms() < 4:
651
+ return False
652
+
653
+ return True
654
+
655
+
656
+ MUTATION_TOKENS = ['[C]', '[N]', '[O]', '[F]', '[Cl]', '[S]', '[*]', 'c', 'n', 'o']
657
+
658
+ # =========================
659
+ # 2. Mutasyon (küçük token değişiklikleri)
660
+ # =========================
661
+ def mutSelfies(individual, max_attempts=5):
662
+ tokens = list(sf.split_selfies(individual[0]))
663
+ if not tokens:
664
+ return individual
665
+
666
+ for _ in range(max_attempts):
667
+ temp_tokens = tokens.copy()
668
+ # Token silme
669
+ if random.random() < 0.3 and len(temp_tokens) > 1:
670
+ idx = random.randint(0, len(temp_tokens) - 1)
671
+ del temp_tokens[idx]
672
+ # Token ekleme
673
+ if random.random() < 0.3:
674
+ idx = random.randint(0, len(temp_tokens))
675
+ new_token = random.choice(MUTATION_TOKENS)
676
+ temp_tokens.insert(idx, new_token)
677
+ # Token değiştirme
678
+ if random.random() < 0.3:
679
+ idx = random.randint(0, len(temp_tokens) - 1)
680
+ temp_tokens[idx] = random.choice(MUTATION_TOKENS)
681
+
682
+ candidate = "".join(temp_tokens)
683
+ if is_valid_polymer(candidate):
684
+ individual[0] = candidate
685
+ return individual
686
+
687
+ # Max deneme sonrası geçerli değilse rastgele valid birey ata
688
+ individual[0] = random.choice(initial_selfies)
689
+ return individual
690
+
691
+
692
+ # =========================
693
+ # 3. Zincir Uzatma
694
+ # =========================
695
+ def extendPolymer(individual, max_add=3):
696
+ tokens = list(sf.split_selfies(individual[0]))
697
+ for _ in range(random.randint(1, max_add)):
698
+ tokens.append(random.choice(['[C]', '[N]', '[O]', '[F]', '[Cl]', '[S]']))
699
+ candidate = "".join(tokens)
700
+ return candidate if is_valid_polymer(candidate) else individual[0]
701
+
702
+
703
+ # =========================
704
+ # 4. Reaction tabanlı mutasyon
705
+ # =========================
706
+ import rdkit.Chem.rdChemReactions as rdChemReactions
707
+ from rdkit.Chem import rdmolops
708
+
709
+ # Örnek reaction havuzu (kendi ihtiyacına göre genişletilebilir)
710
+ REACTION_SMARTS = [
711
+ "[C:1][H:2]>>[C:1]Cl",
712
+ "[C:1][H:2]>>[C:1]O",
713
+ "[C:1](=O)[O;H1].[O;H1][C:2]>>[C:1](=O)O[C:2]",
714
+ "[C:1](=O)Cl.[N:2]>>[C:1](=O)N",
715
+ "[O:1][H].[C:2]Br>>[O:1][C:2]",
716
+ "c1ccccc1>>c1([N+](=O)[O-])ccccc1",
717
+ "[C:1]=[C:2]>>[C:1]-[C:2]"
718
+ ]
719
+
720
+ RDKit_REACTIONS = [rdChemReactions.ReactionFromSmarts(s) for s in REACTION_SMARTS]
721
+
722
+ def chemically_valid_mutate(p_smi: str, reactions=RDKit_REACTIONS, attempts=6):
723
+ """Reaction tabanlı mutasyon uygular; başarısızsa fallback döner."""
724
+ def sanitize_and_canonicalize(smiles):
725
+ try:
726
+ mol = Chem.MolFromSmiles(smiles)
727
+ if mol is None: return None
728
+ rdmolops.SanitizeMol(mol)
729
+ return Chem.MolToSmiles(mol, canonical=True)
730
+ except:
731
+ return None
732
+
733
+ def replace_star_with_H(smi: str):
734
+ return str(smi).replace('*', '[H]')
735
+
736
+ def restore_H_to_star(smi: str):
737
+ return str(smi).replace('[H]', '*')
738
+
739
+ def is_reasonable_product(prod_smiles, max_atoms=120, min_atoms=4):
740
+ if prod_smiles is None: return False
741
+ try:
742
+ m = Chem.MolFromSmiles(prod_smiles)
743
+ if m is None: return False
744
+ n = m.GetNumAtoms()
745
+ if n > max_atoms or n < min_atoms: return False
746
+ try: rdmolops.SanitizeMol(m)
747
+ except: return False
748
+ return True
749
+ except: return False
750
+
751
+ # 1. Prepare
752
+ base = replace_star_with_H(p_smi)
753
+ base_mol = Chem.MolFromSmiles(base)
754
+ if base_mol is None: return p_smi
755
+
756
+ # 2. Reaction denemeleri
757
+ candidate_products = []
758
+ for _ in range(attempts):
759
+ rxn = random.choice(reactions)
760
+ try:
761
+ ps = rxn.RunReactants((base_mol,))
762
+ except:
763
+ ps = ()
764
+ for prod_tuple in ps:
765
+ for prod_mol in prod_tuple:
766
+ try:
767
+ prod_smiles = Chem.MolToSmiles(prod_mol, canonical=True)
768
+ except: prod_smiles = None
769
+ prod_restored = restore_H_to_star(prod_smiles) if prod_smiles else None
770
+ if is_reasonable_product(prod_restored):
771
+ candidate_products.append(prod_restored)
772
+
773
+ # 3. Sonuç
774
+ if candidate_products:
775
+ out = random.choice(candidate_products)
776
+ if out == p_smi or len(out) < max(4, len(p_smi)//2):
777
+ return p_smi
778
+ return out
779
+ return p_smi
780
+
781
+ # =========================
782
+ # 5. Offspring Üretim Fonksiyonu
783
+ # =========================
784
+
785
+ mutation_stats = {'SELFIES':0, 'REACTION':0, 'EXTEND':0, 'NEW':0}
786
+
787
+ def generate_offspring(individual, initial_selfies, mutpb=0.05, extendpb=0.05, newpb=0.01, chempb=0.05):
788
+ """Mutasyon, zincir uzatma, yeni birey ve reaction mutasyonunu uygular."""
789
+ # 1. SELFIES mutasyonu
790
+ if random.random() < mutpb:
791
+ individual = mutSelfies(individual)
792
+ mutation_stats['SELFIES'] += 1
793
+
794
+ # 2. Reaction tabanlı mutasyon
795
+ if random.random() < chempb:
796
+ smi = selfies_to_smiles_safe(individual[0])
797
+ if smi:
798
+ mutated = chemically_valid_mutate(smi)
799
+ ind_selfies = smiles_to_selfies_safe(mutated)
800
+ if ind_selfies:
801
+ individual[0] = ind_selfies
802
+ mutation_stats['REACTION'] += 1
803
+
804
+ # 3. Zincir uzatma
805
+ if random.random() < extendpb:
806
+ individual[0] = extendPolymer(individual)
807
+ mutation_stats['EXTEND'] += 1
808
+
809
+ # 4. Rastgele yeni birey
810
+ if random.random() < newpb:
811
+ individual[0] = random.choice(initial_selfies)
812
+ mutation_stats['NEW'] += 1
813
+
814
+ # 5. Geçerlilik kontrolü
815
+ if not is_valid_polymer(individual[0]):
816
+ individual[0] = random.choice(initial_selfies)
817
+ return individual
818
+
819
+ # =========================
820
+ # 6. run_single_objective_flow Güncellemesi
821
+ # =========================
822
+ def run_single_objective_flow(models, generations, targets, active_props, initial_pop, ranges_dict):
823
+ # --- DEAP Kurulumu ---
824
+ toolbox = base.Toolbox()
825
+ toolbox.register("attr_selfies", random.choice, initial_pop)
826
+ toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_selfies, n=1)
827
+ toolbox.register("population", tools.initRepeat, list, toolbox.individual)
828
+
829
+ # Optimize edilmiş evaluate fonksiyonu
830
+ toolbox.register("evaluate", evaluate_individual_optimized, models=models, targets=targets, active_props=active_props, ranges=ranges_dict)
831
+
832
+ toolbox.register("mate", cxSelfies)
833
+ toolbox.register("select", tools.selTournament, tournsize=7)
834
+
835
+ pop_size = 100
836
+ pop = toolbox.population(n=pop_size)
837
+
838
+ # --- PERFORMANS TAKİP VERİ YAPISI ---
839
+ history = {
840
+ "gen": [],
841
+ "best_fitness": [],
842
+ "avg_fitness": [],
843
+ "diversity": [] # Standart sapma
844
+ }
845
+
846
+ # İlk değerlendirme
847
+ fitnesses = list(map(toolbox.evaluate, pop))
848
+ for ind, fit in zip(pop, fitnesses):
849
+ ind.fitness.values = fit
850
+
851
+ # --- UI Elementleri (Canlı Dashboard) ---
852
+ st.markdown("### 🧬 Evrimsel Süreç İzleme Paneli")
853
+ progress_bar = st.progress(0)
854
+ status_text = st.empty()
855
+
856
+ # Grafikler için yan yana iki kolon (Canlı güncellenecek)
857
+ col_chart1, col_chart2 = st.columns(2)
858
+ with col_chart1:
859
+ st.caption("📉 Yakınsama (Convergence)")
860
+ chart_fitness_placeholder = st.empty()
861
+ with col_chart2:
862
+ st.caption("🌊 Popülasyon Çeşitliliği (Diversity)")
863
+ chart_diversity_placeholder = st.empty()
864
+
865
+ log_expander = st.expander("📝 GA Logları (Detay)", expanded=False)
866
+ with log_expander:
867
+ log_placeholder = st.empty()
868
+ mutation_placeholder = st.empty()
869
+
870
+ log_data = []
871
+
872
+ # --- ANA DÖNGÜ ---
873
+ for gen in range(generations):
874
+ # Adaptif oranlar
875
+ scale = gen / generations
876
+ cxpb = 0.7 - (0.2 * scale)
877
+ mutpb = 0.05 - (0.2 * scale)
878
+ extendpb = 0.05 - (0.15 * scale)
879
+ newpb = 0.01 - (0.05 * scale)
880
+ chempb = 0.05 - (0.15 * scale)
881
+
882
+ # Seçilim ve Klonlama
883
+ offspring = toolbox.select(pop, pop_size)
884
+ offspring = list(map(toolbox.clone, offspring))
885
+
886
+ # Çaprazlama
887
+ for child1, child2 in zip(offspring[::2], offspring[1::2]):
888
+ if random.random() < cxpb:
889
+ toolbox.mate(child1, child2)
890
+ del child1.fitness.values, child2.fitness.values
891
+
892
+ # Mutasyon
893
+ for i in range(len(offspring)):
894
+ if not offspring[i].fitness.valid:
895
+ pass
896
+ offspring[i] = generate_offspring(offspring[i], initial_pop, mutpb=mutpb, extendpb=extendpb, newpb=newpb, chempb=chempb)
897
+ del offspring[i].fitness.values
898
+
899
+ # Değerlendirme
900
+ invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
901
+ fitnesses = map(toolbox.evaluate, invalid_ind)
902
+ for ind, fit in zip(invalid_ind, fitnesses):
903
+ ind.fitness.values = fit
904
+
905
+ pop = offspring
906
+
907
+ # --- İstatistik Toplama (Kritik Bölüm) ---
908
+ # --- ESKİ KOD (SİLİN) ---
909
+ # fits = [ind.fitness.values[0] for ind in pop]
910
+ # best_val = min(fits)
911
+ # mean_val = sum(fits) / len(pop)
912
+ # std_val = np.std(fits)
913
+
914
+ # --- YENİ KOD (BUNU YAPIŞTIRIN) ---
915
+ fits = [ind.fitness.values[0] for ind in pop]
916
+
917
+ # 1. Sadece "Canlı" (Geçerli) bireyleri filtrele (Ceza puanı 999'dan küçük olanlar)
918
+ valid_fits = [f for f in fits if f < 999.0]
919
+
920
+ # 2. İstatistikleri sadece canlılar üzerinden hesapla
921
+ if valid_fits:
922
+ best_val = min(valid_fits) # Zaten min değişmez ama garanti olsun
923
+ mean_val = sum(valid_fits) / len(valid_fits) # GERÇEK ORTALAMA
924
+ std_val = np.std(valid_fits) # GERÇEK ÇEŞİTLİLİK
925
+ else:
926
+ # Herkes öldüyse (Çok nadir olur)
927
+ best_val = 1000.0
928
+ mean_val = 1000.0
929
+ std_val = 0.0
930
+
931
+ # 3. Hayatta Kalma Oranını Hesapla (Survival Rate)
932
+ survival_rate = (len(valid_fits) / len(pop)) * 100
933
+
934
+ # Geçmişe kaydet (survival_rate'i de ekleyebilirsin istersen)
935
+ history["gen"].append(gen)
936
+ history["best_fitness"].append(best_val)
937
+ history["avg_fitness"].append(mean_val)
938
+ history["diversity"].append(std_val)
939
+
940
+ log_data.append({
941
+ "Nesil": gen + 1,
942
+ "En İyi Hata": round(best_val, 4),
943
+ "Ortalama (Valid)": round(mean_val, 4),
944
+ "Canlılık Oranı %": round(survival_rate, 1) # Log tablosunda bunu görmek çok işinize yarar
945
+ })
946
+
947
+ # --- UI Güncelleme (Her adımda veya 2 adımda bir) ---
948
+ if gen % 2 == 0 or gen == generations - 1:
949
+ progress_bar.progress((gen + 1) / generations)
950
+ status_text.markdown(f"**Nesil {gen+1}/{generations}** | En İyi Hata: `{best_val:.4f}` | Çeşitlilik: `{std_val:.4f}`")
951
+
952
+ # 1. Fitness Grafiği Verisi
953
+ df_fit = pd.DataFrame({
954
+ "En İyi (Best)": history["best_fitness"],
955
+ "Ortalama (Avg)": history["avg_fitness"]
956
+ })
957
+ chart_fitness_placeholder.line_chart(df_fit, height=250)
958
+
959
+ # 2. Diversity Grafiği Verisi
960
+ df_div = pd.DataFrame({
961
+ "Çeşitlilik (Std Dev)": history["diversity"]
962
+ })
963
+ # Çeşitlilik grafiğini kırmızı tonla göstermek için (Streamlit varsayılanı kullanır ama veri tek kolon)
964
+ chart_diversity_placeholder.line_chart(df_div, height=250)
965
+
966
+ # Log Tablosu
967
+ df_log = pd.DataFrame(log_data)
968
+ log_placeholder.dataframe(df_log.sort_values(by="Nesil", ascending=False).head(5), use_container_width=True)
969
+ mutation_placeholder.json(mutation_stats)
970
+
971
+ # Sonuç
972
+ best_ind = tools.selBest(pop, 5)[0]
973
+ best_smiles = selfies_to_smiles_safe(best_ind[0])
974
+
975
+ # ... (Yukarıdaki GA döngüsü bittikten sonra) ...
976
+
977
+ # Sonuç - En iyi bireyi seç
978
+ best_ind = tools.selBest(pop, 5)[0]
979
+ best_smiles = selfies_to_smiles_safe(best_ind[0])
980
+
981
+ if best_smiles:
982
+ # 1. Standart Fingerprint (Eski modeller için)
983
+ fp = get_morgan_fp(best_smiles)
984
+
985
+ # 2. Gaz Modeli için Gelişmiş Özellikler (Yeni model için)
986
+ gas_features = get_gas_features_combined(best_smiles)
987
+
988
+ preds = {}
989
+
990
+ # Tüm modeller için tahmin yaparken ayrım yapmalıyız
991
+ for prop in models.keys():
992
+ # ÖZEL DURUM: GasPerma
993
+ if prop == 'GasPerma':
994
+ if gas_features is not None:
995
+ # Model 2054 özellik bekler
996
+ log_pred = models[prop].predict(gas_features)[0]
997
+ # Log10'u geri çevir (10^x)
998
+ preds[prop] = 10 ** log_pred
999
+ else:
1000
+ preds[prop] = 0.0
1001
+
1002
+ # STANDART DURUM: Diğer modeller (Tg, Td, vs.)
1003
+ else:
1004
+ # Modeller sadece 2048 özellik (fp) bekler
1005
+ preds[prop] = models[prop].predict(fp)[0]
1006
+
1007
+ # History sözlüğünü döndürüyoruz
1008
+ return {'smiles': best_smiles, 'preds': preds, 'total_error': best_ind.fitness.values[0]}, history
1009
+ else:
1010
+ return None, history
1011
+
1012
+ import requests
1013
+
1014
+ @st.cache_data
1015
+ def check_pubchem_availability(smiles: str):
1016
+ """
1017
+ Verilen SMILES için PubChem'de kayıtlı mı kontrol eder.
1018
+ Yıldızları (*) temizleyerek arama yapar.
1019
+ """
1020
+ # DÜZELTME: Yıldızları temizle veya Hidrojene çevir
1021
+ clean_smi = smiles.replace('*', '')
1022
+
1023
+ # URL encoded hale getirmek gerekebilir ama requests bunu genelde yapar.
1024
+ url = f"https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/smiles/{clean_smi}/cids/JSON"
1025
+
1026
+ try:
1027
+ response = requests.get(url, timeout=5)
1028
+
1029
+ # 404 (Bulunamadı) normaldir, hata fırlatmasın
1030
+ if response.status_code == 404:
1031
+ return False, None, None
1032
+
1033
+ response.raise_for_status()
1034
+ data = response.json()
1035
+
1036
+ if "IdentifierList" in data and "CID" in data["IdentifierList"]:
1037
+ cid = data["IdentifierList"]["CID"][0]
1038
+
1039
+ # İsim sorgusu
1040
+ name_url = f"https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/cid/{cid}/property/IUPACName/JSON"
1041
+ name_resp = requests.get(name_url, timeout=5)
1042
+ if name_resp.status_code == 200:
1043
+ name_data = name_resp.json()
1044
+ name = name_data["PropertyTable"]["Properties"][0].get("IUPACName", "Bilinmiyor")
1045
+ else:
1046
+ name = "Bilinmiyor"
1047
+
1048
+ return True, cid, name
1049
+ else:
1050
+ return False, None, None
1051
+
1052
+ except Exception:
1053
+ # Hata olsa bile uygulamayı durdurma, sessizce geç
1054
+ return False, None, None
1055
+ # --- TİCARİ KONTROL FONKSİYONU ---
1056
+ def check_commercial_availability(query):
1057
+ """
1058
+ Verilen ismi veya SMILES'ı PubChem'de arar.
1059
+ Ticari olarak satılıp satılmadığını (Vendor sayısı) kontrol eder.
1060
+ """
1061
+ try:
1062
+ # İsim veya SMILES ile arama yap
1063
+ compounds = pcp.get_compounds(query, 'name')
1064
+ if not compounds:
1065
+ compounds = pcp.get_compounds(query, 'smiles')
1066
+
1067
+ if compounds:
1068
+ cid = compounds[0].cid
1069
+ # PubChem'den "Vendor" (Satıcı) bilgisini çekmek biraz daha karmaşıktır,
1070
+ # bu yüzden basitçe "Kayıt var mı?" kontrolü yapıyoruz.
1071
+ # Kayıt varsa %99 ticaridir veya sentezlenebilir.
1072
+ synonyms = compounds[0].synonyms
1073
+ common_name = synonyms[0] if synonyms else query
1074
+ return True, cid, common_name
1075
+ else:
1076
+ return False, None, None
1077
+ except:
1078
+ return False, None, None
1079
+ def make_3d_view_with_reason(smiles):
1080
+ try:
1081
+ clean_smi = str(smiles).replace('*', '[H]')
1082
+ mol = Chem.MolFromSmiles(clean_smi)
1083
+ if mol is None:
1084
+ return None, "SMILES geçersiz veya RDKit ile molekül oluşturulamadı."
1085
+
1086
+ mol = Chem.AddHs(mol)
1087
+ if AllChem.EmbedMolecule(mol) != 0:
1088
+ return None, "3D koordinatlar hesaplanamadı (Embed başarısız)."
1089
+
1090
+ try:
1091
+ AllChem.MMFFOptimizeMolecule(mol)
1092
+ except:
1093
+ return None, "3D yapı enerji optimizasyonunda başarısız."
1094
+
1095
+ mblock = Chem.MolToMolBlock(mol)
1096
+ view = py3Dmol.view(width=400, height=400)
1097
+ view.addModel(mblock, 'mol')
1098
+ view.setStyle({'stick':{'colorscheme':'Jmol'}})
1099
+ view.zoomTo()
1100
+ view.spin(True)
1101
+ return view, None
1102
+ except Exception as e:
1103
+ return None, f"Beklenmeyen bir hata: {e}"
1104
+
1105
+ def get_ai_interpretation(api_key, smiles, preds, targets, active_props):
1106
+ """Gemini API kullanarak polimer analizi yapar."""
1107
+ if not api_key:
1108
+ return "⚠️ Analiz için lütfen sol menüden geçerli bir Google Gemini API Anahtarı giriniz."
1109
+
1110
+ try:
1111
+ genai.configure(api_key=api_key)
1112
+ model = genai.GenerativeModel('gemini-2.5-flash') # Hızlı ve ekonomik model
1113
+
1114
+ # Dinamik Prompt Hazırlama
1115
+ prompt = f"""
1116
+ Sen uzman bir Polimer Kimyagerisin ve Malzeme Bilimci'sin.
1117
+ Aşağıda genetik algoritma ile üretilmiş yeni bir polimer adayı var.
1118
+
1119
+ Molekül (SMILES): {smiles}
1120
+
1121
+ Tahmin Edilen Özellikler:
1122
+ """
1123
+
1124
+ for prop in active_props:
1125
+ target_val = targets.get(prop, "Belirtilmedi")
1126
+ pred_val = preds.get(prop, 0.0)
1127
+ prompt += f"- {prop}: Tahmin={pred_val:.2f} (Hedef={target_val})\n"
1128
+
1129
+ prompt += """
1130
+
1131
+ Lütfen bu polimeri şu başlıklar altında Türkçe olarak detaylıca analiz et:
1132
+ 1. **Yapı-Özellik İlişkisi:** Bu yapısal özellikler (halkalar, fonksiyonel gruplar, zincir uzunluğu vb.) neden bu tahmin değerlerini (özellikle Tg ve Td) ortaya çıkarmış olabilir? Kimyasal mantığı nedir?
1133
+ 2. **Potansiyel Uygulama Alanları:** Bu özelliklere sahip bir polimer endüstride nerede kullanılabilir? (Örn: Havacılık, paketleme, elektronik, membran vb.)
1134
+ 3. **Sentezlenebilirlik Yorumu:** Yapıya bakarak sentez zorluğu veya stabilite hakkında kısa bir yorum yap.
1135
+
1136
+ Yanıtın profesyonel, bilimsel ama anlaşılır olsun. Markdown formatı kullan.
1137
+ """
1138
+
1139
+ with st.spinner('Yapay Zeka polimeri inceliyor...'):
1140
+ response = model.generate_content(prompt)
1141
+ return response.text
1142
+
1143
+ except Exception as e:
1144
+ return f"❌ AI Bağlantı Hatası: {str(e)}"
1145
+ # --- SA Score Fonksiyonu ---
1146
+
1147
+ def get_sa_score_local(p_smiles):
1148
+ """
1149
+ Yerel SA Score Hesaplayıcı.
1150
+ Eğer klasörde 'sascorer.py' varsa onu kullanır, yoksa basit hesaplama yapar.
1151
+ """
1152
+ try:
1153
+ import sascorer
1154
+ smi_clean = str(p_smiles).replace('*', '[H]').replace('(*)', '[H]').replace('[*]', '[H]')
1155
+ mol = Chem.MolFromSmiles(smi_clean)
1156
+ if mol is None:
1157
+ raise ValueError("Mol oluşturulamadı")
1158
+ return sascorer.calculateScore(mol)
1159
+ except:
1160
+ # Basit yedek hesaplama: uzunluk ve halka sayısına göre
1161
+ length = len(str(p_smiles))
1162
+ score = 2.0 + (length * 0.05)
1163
+ if "c1" in str(p_smiles):
1164
+ score += 0.5
1165
+ return min(score, 10.0)
1166
+ # =========================================================================
1167
+ # VII. YEŞİL KİMYA / SÜRDÜRÜLEBİLİRLİK MOTORU
1168
+ # =========================================================================
1169
+
1170
+ def calculate_green_score(smiles):
1171
+ """
1172
+ Polimerin potansiyel biyo-bozunurluğunu ve çevresel etkisini puanlar.
1173
+ Puan: 1 (Çok Kötü/Kalıcı) - 10 (Mükemmel/Bozunabilir)
1174
+ """
1175
+ mol = Chem.MolFromSmiles(smiles.replace('*', '[H]'))
1176
+ if not mol: return 0, "Hesaplanamadı", "#7f8c8d"
1177
+
1178
+ score = 5.0 # Nötr başlangıç
1179
+ notes = []
1180
+
1181
+ # --- 1. BOZUNABİLİR BAĞLAR (Pozitif) ---
1182
+ # Ester Bağı: Hidroliz olur, doğada parçalanır (Örn: PLA)
1183
+ if mol.HasSubstructMatch(Chem.MolFromSmarts("[C;!R](=[O])[O;!R]")):
1184
+ score += 3.0
1185
+ notes.append("Ester bağı (Hidroliz olabilir)")
1186
+
1187
+ # Amid Bağı: Enzimlerle parçalanabilir (Örn: Proteinler, Naylon)
1188
+ if mol.HasSubstructMatch(Chem.MolFromSmarts("[C;!R](=[O])[N;!R]")):
1189
+ score += 2.0
1190
+ notes.append("Amid bağı (Biyo-bozunurluk potansiyeli)")
1191
+
1192
+ # Eter Bağı (PEG gibi): Suda çözünürlük sağlar, biyolojik atılımı kolaylaştırır
1193
+ if mol.HasSubstructMatch(Chem.MolFromSmarts("[C][O][C]")):
1194
+ score += 1.0
1195
+ notes.append("Eter grubu (Hidrofilik özellik)")
1196
+
1197
+ # --- 2. KALICILIK ve TOKSİSİTE (Negatif) ---
1198
+ # Halojenler (F, Cl, Br): Doğada birikim yapar, toksiktir (Örn: PVC, Teflon)
1199
+ halogens = [atom.GetSymbol() for atom in mol.GetAtoms() if atom.GetSymbol() in ['F', 'Cl', 'Br']]
1200
+ if halogens:
1201
+ count = len(halogens)
1202
+ penalty = min(4.0, count * 1.0) # En fazla 4 puan kır
1203
+ score -= penalty
1204
+ notes.append(f"{count} adet Halojen atomu (Kalıcılık/Toksisite riski)")
1205
+
1206
+ # Aromatik Halkalar: Bakterilerin parçalaması zordur
1207
+ aromatic_atoms = [atom for atom in mol.GetAtoms() if atom.GetIsAromatic()]
1208
+ if len(aromatic_atoms) > 4: # Çok fazla halka varsa
1209
+ score -= 2.0
1210
+ notes.append("Yüksek Aromatiklik (Zor parçalanma)")
1211
+
1212
+ # --- 3. SONUÇ SINIRLANDIRMA ---
1213
+ score = max(1.0, min(10.0, score)) # 1-10 arasına sabitle
1214
+
1215
+ # Renk Kodu Belirle
1216
+ if score >= 7.0: color = "#2ecc71" # Yeşil (İyi)
1217
+ elif score >= 4.0: color = "#f1c40f" # Sarı (Orta)
1218
+ else: color = "#e74c3c" # Kırmızı (Kötü)
1219
+
1220
+ return score, ", ".join(notes), color
1221
+ import plotly.graph_objects as go
1222
+
1223
+ def create_radar_chart(preds, targets, active_props, ranges):
1224
+ """
1225
+ Hedeflenen özellikler ile tahmin edilen özellikleri karşılaştıran
1226
+ havalı bir Radar (Spider) Grafiği çizer.
1227
+ """
1228
+ categories = []
1229
+ target_values = []
1230
+ pred_values = []
1231
+
1232
+ for prop in active_props:
1233
+ if prop in preds and prop in targets:
1234
+ # Başlıkları güzelleştir
1235
+ label = prop
1236
+ if prop == 'ThermalCond': label = 'Iletkenlik'
1237
+ if prop == 'Solubility': label = 'Cozunurluk'
1238
+
1239
+ categories.append(label)
1240
+
1241
+ # Değerleri al
1242
+ t_val = targets[prop]
1243
+ p_val = preds[prop]
1244
+
1245
+ # Normalizasyon (Grafikte düzgün durması için 0-1 arasına çekiyoruz)
1246
+ # Min-Max normalizasyonu
1247
+ min_v = ranges[prop]['min']
1248
+ max_v = ranges[prop]['max']
1249
+
1250
+ # Sıfıra bölme hatası önlemi
1251
+ if max_v - min_v == 0: denom = 1
1252
+ else: denom = max_v - min_v
1253
+
1254
+ norm_t = (t_val - min_v) / denom
1255
+ norm_p = (p_val - min_v) / denom
1256
+
1257
+ # Sınırlandırma (Grafik dışına taşmasın)
1258
+ norm_t = max(0.0, min(1.0, norm_t))
1259
+ norm_p = max(0.0, min(1.0, norm_p))
1260
+
1261
+ target_values.append(norm_t)
1262
+ pred_values.append(norm_p)
1263
+
1264
+ # Grafiği kapatmak için ilk değeri sona ekle
1265
+ categories = categories + [categories[0]]
1266
+ target_values = target_values + [target_values[0]]
1267
+ pred_values = pred_values + [pred_values[0]]
1268
+
1269
+ fig = go.Figure()
1270
+
1271
+ # Hedef Alanı (Mavi Çizgi)
1272
+ fig.add_trace(go.Scatterpolar(
1273
+ r=target_values,
1274
+ theta=categories,
1275
+ fill='toself',
1276
+ name='Hedeflenen',
1277
+ line=dict(color='#3498db', dash='dash')
1278
+ ))
1279
+
1280
+ # Tahmin Alanı (Kırmızı Dolgu)
1281
+ fig.add_trace(go.Scatterpolar(
1282
+ r=pred_values,
1283
+ theta=categories,
1284
+ fill='toself',
1285
+ name='Uretilen Polimer',
1286
+ line=dict(color='#e74c3c'),
1287
+ opacity=0.7
1288
+ ))
1289
+
1290
+ fig.update_layout(
1291
+ polar=dict(
1292
+ radialaxis=dict(
1293
+ visible=True,
1294
+ range=[0, 1] # Normalize ettiğimiz için 0-1 arası
1295
+ )),
1296
+ showlegend=True,
1297
+ margin=dict(l=40, r=40, t=20, b=20),
1298
+ height=300 # Kompakt boyut
1299
+ )
1300
+
1301
+ return fig
1302
+ # =========================================================================
1303
+ # VI. RETROSENTEZ MOTORU (Yeni Eklenen Kısım)
1304
+ # =========================================================================
1305
+
1306
+ # =========================================================================
1307
+ # GÜNCELLENMİŞ RETROSENTEZ MOTORU (Imide Desteği Eklendi)
1308
+ # =========================================================================
1309
+
1310
+ # =========================================================================
1311
+ # GÜNCELLENMİŞ RETROSENTEZ MOTORU v2.0 (Akıllı Varsayılan Eklendi)
1312
+ # =========================================================================
1313
+
1314
+ # =========================================================================
1315
+ # GÜNCELLENMİŞ RETROSENTEZ MOTORU v3.0 (Poliüre & Poliüretan Eklendi)
1316
+ # =========================================================================
1317
+
1318
+ def decompose_polymer(smiles):
1319
+ """
1320
+ Polimeri parçalar. v3.0: Üre ve Üretan bağlarını da tanır.
1321
+ """
1322
+ clean_smi = smiles.replace('*', '[H]')
1323
+ mol = Chem.MolFromSmiles(clean_smi)
1324
+ if not mol: return None, "Geçersiz Molekül"
1325
+
1326
+ breakdown_results = []
1327
+
1328
+ # --- KURAL 1: İMİD (Poliimid) ---
1329
+ imide_pattern = Chem.MolFromSmarts("[CX3](=[OX1])[#7][CX3](=[OX1])")
1330
+ if mol.HasSubstructMatch(imide_pattern):
1331
+ return [{
1332
+ "type": "Poliimid Sentezi",
1333
+ "reaction": "Siklo-dehidrasyon",
1334
+ "monomers": ["Dianhidrit", "Diamin"],
1335
+ "mechanism": "Dianhidrit + Diamin -> Poliimid"
1336
+ }]
1337
+
1338
+ # --- KURAL 2: ÜRE (Polyurea) --- [YENİ]
1339
+ # R-NH-C(=O)-NH-R' -> R-N=C=O (İzosiyanat) + H2N-R' (Amin)
1340
+ urea_pattern = Chem.MolFromSmarts("[N;!R][C;!R](=[O])[N;!R]")
1341
+ if mol.HasSubstructMatch(urea_pattern):
1342
+ breakdown_results.append({
1343
+ "type": "Poliüre (Polyurea) Sentezi",
1344
+ "reaction": "Basamaklı Polimerizasyon (Hızlı)",
1345
+ "monomers": ["Diizosiyanat (Diisocyanate)", "Diamin (Diamine)"],
1346
+ "mechanism": "İzosiyanat + Amin -> Üre Bağı (Yan ürün yok)"
1347
+ })
1348
+
1349
+ # --- KURAL 3: ÜRETAN (Polyurethane) --- [YENİ]
1350
+ # R-NH-C(=O)-O-R' -> R-N=C=O (İzosiyanat) + HO-R' (Alkol/Polyol)
1351
+ urethane_pattern = Chem.MolFromSmarts("[N;!R][C;!R](=[O])[O;!R]")
1352
+ if mol.HasSubstructMatch(urethane_pattern):
1353
+ breakdown_results.append({
1354
+ "type": "Poliüretan (PU) Sentezi",
1355
+ "reaction": "Poliladisyon",
1356
+ "monomers": ["Diizosiyanat (Örn: TDI, MDI)", "Diol / Polyol"],
1357
+ "mechanism": "İzosiyanat + Alkol -> Üretan Bağı"
1358
+ })
1359
+
1360
+ # --- KURAL 4: ESTER (Polyester) ---
1361
+ ester_pattern = Chem.MolFromSmarts("[C;!R](=[O])[O;!R]")
1362
+ if mol.HasSubstructMatch(ester_pattern) and not breakdown_results: # Üretan değilse bak
1363
+ breakdown_results.append({
1364
+ "type": "Polyester Sentezi",
1365
+ "reaction": "Kademeli Polimerizasyon",
1366
+ "monomers": ["Dikarboksilik Asit", "Diol"],
1367
+ "mechanism": "Asit + Alkol -> Ester + Su"
1368
+ })
1369
+
1370
+ # --- KURAL 5: AMİD (Nylon) ---
1371
+ amide_pattern = Chem.MolFromSmarts("[C;!R](=[O])[N;!R]")
1372
+ if mol.HasSubstructMatch(amide_pattern) and not breakdown_results: # Üre değilse bak
1373
+ breakdown_results.append({
1374
+ "type": "Poliamid (Nylon) Sentezi",
1375
+ "reaction": "Polikondenzasyon",
1376
+ "monomers": ["Dikarboksilik Asit", "Diamin"],
1377
+ "mechanism": "Asit + Amin -> Amid + Su"
1378
+ })
1379
+
1380
+ # --- VARSAYILAN ---
1381
+ if not breakdown_results:
1382
+ # Akıllı kontrol: Azot/Oksijen var mı?
1383
+ has_hetero = any(atom.GetSymbol() in ['N', 'O', 'S'] for atom in mol.GetAtoms())
1384
+ if has_hetero and "C=C" not in smiles:
1385
+ breakdown_results.append({
1386
+ "type": "Kompleks Kondenzasyon Polimeri",
1387
+ "reaction": "Özel Sentez (AI Analizi Önerilir)",
1388
+ "monomers": ["Fonksiyonel Grup A", "Fonksiyonel Grup B"],
1389
+ "mechanism": "Uç grupların reaksiyonu"
1390
+ })
1391
+ else:
1392
+ breakdown_results.append({
1393
+ "type": "Vinil Polimerizasyonu (Katılma)",
1394
+ "reaction": "Radikalik",
1395
+ "monomers": [smiles.replace('*', '')],
1396
+ "mechanism": "Çift bağ açılması"
1397
+ })
1398
+
1399
+ return breakdown_results
1400
+ def draw_retrosynthesis_grid(monomer_smiles_list):
1401
+ """Monomerlerin listesini alır ve yan yana çizer."""
1402
+ mols = [Chem.MolFromSmiles(s) for s in monomer_smiles_list]
1403
+ mols = [m for m in mols if m is not None] # Hatalıları temizle
1404
+ if not mols: return None
1405
+
1406
+ img = Draw.MolsToGridImage(
1407
+ mols,
1408
+ molsPerRow=min(len(mols), 3),
1409
+ subImgSize=(200, 200),
1410
+ legends=[f"Monomer {i+1}" for i in range(len(mols))]
1411
+ )
1412
+ return img
1413
+
1414
+ def get_ai_retrosynthesis_guide(api_key, polymer_smiles, monomer_info):
1415
+ """Gemini'den detaylı sentez rotası ister."""
1416
+ if not api_key: return "⚠️ Detaylı sentez planı için API Key gerekli."
1417
+
1418
+ try:
1419
+ genai.configure(api_key=api_key)
1420
+ model = genai.GenerativeModel('gemini-2.5-flash')
1421
+
1422
+ prompt = f"""
1423
+ Sen uzman bir Sentetik Polimer Kimyagerisin.
1424
+ Aşağıdaki polimer için endüstriyel veya laboratuvar ölçekli bir RETROSENTEZ (geriye dönük sentez) planı hazırla.
1425
+
1426
+ Hedef Polimer (SMILES): {polymer_smiles}
1427
+ Algarlanan Olası Yöntem: {monomer_info}
1428
+
1429
+ Lütfen şu formatta yanıtla:
1430
+ 1. **Önerilen Monomerler:** Bu yapıyı oluşturmak için hangi ticari kimyasallar (IUPAC isimleri) gerekir?
1431
+ 2. **Sentez Yöntemi:** Hangi reaksiyon türü uygundur? (Örn: Radikalik, Kondenzasyon, ROMP?)
1432
+ 3. **Kritik Koşullar:** Sıcaklık, basınç veya spesifik katalizör (AIBN, Ziegler-Natta, H2SO4 vb.) önerisi.
1433
+ 4. **Zorluk Analizi:** Bu sentezin pratik zorlukları nelerdir?
1434
+
1435
+ Kısa, net ve bilimsel olsun.
1436
+ """
1437
+ with st.spinner('AI Sentez Rotasını Hesaplıyor...'):
1438
+ response = model.generate_content(prompt)
1439
+ return response.text
1440
+ except Exception as e:
1441
+ return f"Hata: {str(e)}"
1442
+ from fpdf import FPDF
1443
+ import tempfile
1444
+
1445
+ class PDFReport(FPDF):
1446
+ def header(self):
1447
+ self.set_font('Arial', 'B', 15)
1448
+ self.cell(0, 10, 'PolimerX - Ar-Ge Proje Raporu', 0, 1, 'C')
1449
+ self.ln(5)
1450
+
1451
+ def footer(self):
1452
+ self.set_y(-15)
1453
+ self.set_font('Arial', 'I', 8)
1454
+ self.cell(0, 10, f'Sayfa {self.page_no()}', 0, 0, 'C')
1455
+
1456
+ def clean_text(text):
1457
+ """FPDF için Türkçe karakterleri ASCII'ye çevirir (Hızlı çözüm)"""
1458
+ replacements = {
1459
+ 'ğ': 'g', 'Ğ': 'G', 'ü': 'u', 'Ü': 'U', 'ş': 's', 'Ş': 'S',
1460
+ 'ı': 'i', 'İ': 'I', 'ö': 'o', 'Ö': 'O', 'ç': 'c', 'Ç': 'C'
1461
+ }
1462
+ for search, replace in replacements.items():
1463
+ text = text.replace(search, replace)
1464
+ return text.encode('latin-1', 'replace').decode('latin-1')
1465
+
1466
+ def create_pdf_report(poly_data, targets, active_props, ai_analysis_text, retro_info):
1467
+ pdf = PDFReport()
1468
+ pdf.add_page()
1469
+ pdf.set_font("Arial", size=12)
1470
+
1471
+ # 1. Başlık Bilgileri
1472
+ pdf.set_font("Arial", 'B', 14)
1473
+ pdf.cell(0, 10, clean_text("1. Polimer Özellik Tablosu"), 0, 1)
1474
+ pdf.set_font("Arial", size=10)
1475
+
1476
+ # Tablo Başlığı
1477
+ pdf.set_fill_color(200, 220, 255)
1478
+ pdf.cell(60, 8, "Ozellik", 1, 0, 'C', 1)
1479
+ pdf.cell(60, 8, "Hedef", 1, 0, 'C', 1)
1480
+ pdf.cell(60, 8, "Tahmin Degeri", 1, 1, 'C', 1)
1481
+
1482
+ # --- GÜNCELLEME: Tüm tahminleri döngüye al ---
1483
+ all_preds = poly_data['preds']
1484
+
1485
+ for prop, val in all_preds.items():
1486
+ # Hedeflenen değer var mı kontrol et
1487
+ if prop in active_props:
1488
+ target_val = str(targets.get(prop, '-'))
1489
+ # Hedeflenenleri kalın (bold) veya işaretli gösterebiliriz ama
1490
+ # şimdilik standart formatta yazıyoruz.
1491
+ else:
1492
+ target_val = "-" # Hedef belirtilmedi
1493
+
1494
+ pred_val = f"{val:.2f}"
1495
+
1496
+ # Satırı yaz
1497
+ pdf.cell(60, 8, clean_text(prop), 1)
1498
+ pdf.cell(60, 8, target_val, 1)
1499
+ pdf.cell(60, 8, pred_val, 1, 1)
1500
+
1501
+ pdf.ln(10)
1502
+
1503
+ # 2. Molekül Görseli
1504
+ pdf.set_font("Arial", 'B', 14)
1505
+ pdf.cell(0, 10, clean_text("2. Molekuler Yapi"), 0, 1)
1506
+
1507
+ # SMILES
1508
+ pdf.set_font("Courier", size=8)
1509
+ pdf.multi_cell(0, 5, poly_data['smiles'])
1510
+ pdf.ln(5)
1511
+
1512
+ # Görseli ekle
1513
+ mol_img = draw_2d_molecule(poly_data['smiles'])
1514
+ if mol_img:
1515
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmp_file:
1516
+ mol_img.save(tmp_file.name)
1517
+ pdf.image(tmp_file.name, x=60, w=90)
1518
+
1519
+ pdf.ln(10)
1520
+
1521
+ # 3. Retrosentez Bilgisi
1522
+ pdf.set_font("Arial", 'B', 14)
1523
+ pdf.cell(0, 10, clean_text("3. Uretim Plani (Retrosentez)"), 0, 1)
1524
+ pdf.set_font("Arial", size=10)
1525
+
1526
+ if not retro_info or len(retro_info) < 5:
1527
+ pdf.multi_cell(0, 6, clean_text("Retrosentez analizi yapilmadi veya veri yok."))
1528
+ else:
1529
+ clean_retro = clean_text(str(retro_info))
1530
+ pdf.multi_cell(0, 6, clean_retro)
1531
+
1532
+ pdf.ln(10)
1533
+
1534
+ # 4. AI Yorumu
1535
+ pdf.set_font("Arial", 'B', 14)
1536
+ pdf.cell(0, 10, clean_text("4. Yapay Zeka Uzman Görüşü"), 0, 1)
1537
+ pdf.set_font("Arial", size=10)
1538
+
1539
+ if not ai_analysis_text or len(ai_analysis_text) < 5:
1540
+ pdf.multi_cell(0, 6, clean_text("AI analizi talep edilmedi."))
1541
+ else:
1542
+ clean_ai = clean_text(ai_analysis_text).replace('**', '').replace('#', '')
1543
+ pdf.multi_cell(0, 6, clean_ai)
1544
+
1545
+ return pdf.output(dest='S').encode('latin-1')
1546
+ from rdkit import DataStructs
1547
+
1548
+ @st.cache_data
1549
+ def get_reference_fingerprints(smiles_list):
1550
+ """
1551
+ Referans veri setindeki tüm SMILES'ların parmak izlerini önceden hesaplar ve önbelleğe alır.
1552
+ Bu işlem sadece bir kez yapılır, böylece uygulama hızlanır.
1553
+ """
1554
+ fps = []
1555
+ names = [] # Varsa isimleri, yoksa SMILES'ın kendisi
1556
+
1557
+ for i, smi in enumerate(smiles_list):
1558
+ try:
1559
+ mol = Chem.MolFromSmiles(str(smi).replace('*', '[H]'))
1560
+ if mol:
1561
+ fp = AllChem.GetMorganFingerprintAsBitVect(mol, 3, 2048)
1562
+ fps.append(fp)
1563
+ names.append(f"Veri Seti Kaydı #{i+1}") # Veya smi
1564
+ except:
1565
+ continue
1566
+ return fps, names
1567
+
1568
+ def calculate_novelty_optimized(generated_smiles, ref_smiles_list):
1569
+ """
1570
+ Toplu Tanimoto benzerliği hesaplar (Çok hızlıdır).
1571
+ """
1572
+ # 1. Üretilen molekülün parmak izi
1573
+ gen_mol = Chem.MolFromSmiles(generated_smiles.replace('*', '[H]'))
1574
+ if not gen_mol: return 0.0, "Hesaplanamadı"
1575
+ gen_fp = AllChem.GetMorganFingerprintAsBitVect(gen_mol, 3, 2048)
1576
+
1577
+ # 2. Referans parmak izlerini önbellekten çek
1578
+ ref_fps, ref_names = get_reference_fingerprints(ref_smiles_list)
1579
+
1580
+ if not ref_fps: return 0.0, "Veri Seti Boş"
1581
+
1582
+ # 3. RDKit'in Toplu (Bulk) Karşılaştırma Fonksiyonu
1583
+ # Bu döngüden 100 kat daha hızlıdır.
1584
+ sims = DataStructs.BulkTanimotoSimilarity(gen_fp, ref_fps)
1585
+
1586
+ # 4. En yüksek benzerliği bul
1587
+ max_sim = max(sims)
1588
+ max_idx = sims.index(max_sim)
1589
+ most_similar_name = ref_names[max_idx]
1590
+
1591
+ # Eşleşen SMILES'ı döndürmek daha bilgilendirici olabilir
1592
+ most_similar_smiles = ref_smiles_list[max_idx] if max_idx < len(ref_smiles_list) else "Bilinmiyor"
1593
+
1594
+ return max_sim, most_similar_smiles
1595
+ # =========================================================================
1596
+ # IV. STREAMLIT ANA KISIM
1597
+ # =========================================================================
1598
+
1599
+ # st.title("...") yerine:
1600
+
1601
+ st.markdown('<h1 class="main-title">🧬 PolimerX <br><span style="font-size:1.5rem; color:#666; font-weight:400;">Yapay Zeka Destekli Materyal Keşfi</span></h1>', unsafe_allow_html=True)
1602
+
1603
+ models = load_critic_models()
1604
+ ALL_PROPS = list(models.keys()) # Yüklenen modellerin anahtarları: ['Tg', 'Td', 'EPS']
1605
+
1606
+ # --- Yardımcı: Senkron Slider + Number input ---
1607
+ def add_synced_input(prop_key, label, min_val, max_val, default, step, is_int=False):
1608
+ """Sidebar üzerinde bir slider ve number_input oluşturur; ikisini session_state üzerinden senkronlar.
1609
+ Döndürülen değer her zaman current value (float/int) olur.
1610
+ """
1611
+ s_key = f"{prop_key}_val"
1612
+ slider_key = f"{prop_key}_slider"
1613
+ num_key = f"{prop_key}_num"
1614
+
1615
+ # Başlangıç değeri session_state'e konur
1616
+ if s_key not in st.session_state:
1617
+ st.session_state[s_key] = default
1618
+ if slider_key not in st.session_state:
1619
+ st.session_state[slider_key] = st.session_state[s_key]
1620
+ if num_key not in st.session_state:
1621
+ st.session_state[num_key] = st.session_state[s_key]
1622
+
1623
+ def _on_slider_change():
1624
+ # slider değiştiğinde number_input değerini güncelle
1625
+ try:
1626
+ st.session_state[num_key] = st.session_state[slider_key]
1627
+ st.session_state[s_key] = st.session_state[slider_key]
1628
+ except Exception:
1629
+ pass
1630
+
1631
+ def _on_num_change():
1632
+ # number_input değiştiğinde slider'ı güncelle
1633
+ try:
1634
+ st.session_state[slider_key] = st.session_state[num_key]
1635
+ st.session_state[s_key] = st.session_state[num_key]
1636
+ except Exception:
1637
+ pass
1638
+
1639
+ # Slider (min/max tipi int/float ile uyumlu olmalı)
1640
+ if is_int:
1641
+ st.sidebar.slider(label + " (slider)", min_value=int(min_val), max_value=int(max_val), step=int(step), key=slider_key, on_change=_on_slider_change)
1642
+ st.sidebar.number_input(label + " (value)", min_value=int(min_val), max_value=int(max_val), step=int(step), key=num_key, on_change=_on_num_change)
1643
+ else:
1644
+ st.sidebar.slider(label + " (slider)", min_value=float(min_val), max_value=float(max_val), step=float(step), key=slider_key, on_change=_on_slider_change)
1645
+ st.sidebar.number_input(label + " (value)", min_value=float(min_val), max_value=float(max_val), step=float(step), format="%.4f", key=num_key, on_change=_on_num_change)
1646
+
1647
+ return st.session_state[s_key]
1648
+
1649
+ if models:
1650
+ st.sidebar.header("⚙️ Hedef Seçimi")
1651
+
1652
+ # 1. Optimizasyona Dahil Edilecek Özelliklerin Seçimi
1653
+ active_props = []
1654
+
1655
+ st.sidebar.markdown("### Dahil Edilecek Özellikler")
1656
+ # Her özellik için onay kutusu oluştur
1657
+ if st.sidebar.checkbox("Tg (Camsı Geçiş Sıcaklığı)", value=True):
1658
+ active_props.append('Tg')
1659
+ if st.sidebar.checkbox("Td (Bozunma Sıcaklığı)"):
1660
+ active_props.append('Td')
1661
+ if st.sidebar.checkbox("EPS (Dielektrik Sabiti)"):
1662
+ active_props.append('EPS')
1663
+ if st.sidebar.checkbox("Tm (Erime Sıcaklığı)"):
1664
+ active_props.append('Tm')
1665
+ if st.sidebar.checkbox("Bandgap Bulk (Elektriksel Band Aralığı - Bulk)"):
1666
+ active_props.append('BandgapBulk')
1667
+ if st.sidebar.checkbox("Bandgap Chain (Elektriksel Band Aralığı - Zincir)"):
1668
+ active_props.append('BandgapChain')
1669
+ if st.sidebar.checkbox("Bandgap Crystal (Elektriksel Band Aralığı - Kristal)"):
1670
+ active_props.append('BandgapCrystal')
1671
+ if st.sidebar.checkbox("Gas Permeability (Gaz Geçirgenliği)"):
1672
+ active_props.append('GasPerma')
1673
+ if st.sidebar.checkbox("Refractive Index (Kırılma İndeksi)"):
1674
+ active_props.append('Refractive')
1675
+
1676
+ if st.sidebar.checkbox("LOI (Yanıcılık İndeksi)"):
1677
+ active_props.append('LOI')
1678
+
1679
+ if st.sidebar.checkbox("Çözünürlük (Hildebrand)"):
1680
+ active_props.append('Solubility')
1681
+
1682
+ if st.sidebar.checkbox("Isıl İletkenlik (Thermal Cond.)"):
1683
+ active_props.append('ThermalCond')
1684
+
1685
+ if st.sidebar.checkbox("Isıl Genleşme (CTE)"):
1686
+ active_props.append('CTE')
1687
+ # En az bir hedef seçilmemişse uyarı ver
1688
+
1689
+ if not active_props:
1690
+ st.sidebar.warning("Lütfen optimize edilecek en az bir hedef seçin.")
1691
+ st.stop()
1692
+
1693
+ # 2. Hedef Değerler (Sadece seçilenler için giriş alanı göster)
1694
+ st.sidebar.markdown("### Hedef Değerler")
1695
+ targets = {}
1696
+
1697
+ # Önerilen aralıklar (kullanıcının onayladığı değerler)
1698
+ # Sıcaklıklar (°C)
1699
+ ranges = {
1700
+ 'Tg': {'min': -150.0, 'max': 300.0, 'default': 200.0, 'step': 1.0, 'is_int': False},
1701
+ 'Td': {'min': 150.0, 'max': 600.0, 'default': 350.0, 'step': 1.0, 'is_int': False},
1702
+ 'Tm': {'min': 50.0, 'max': 450.0, 'default': 250.0, 'step': 1.0, 'is_int': False},
1703
+ # Diğer özellikler
1704
+ 'EPS': {'min': 1.5, 'max': 12.0, 'default': 2.5, 'step': 0.1, 'is_int': False},
1705
+ 'BandgapBulk': {'min': 0.5, 'max': 6.0, 'default': 2.5, 'step': 0.01, 'is_int': False},
1706
+ 'BandgapChain': {'min': 0.5, 'max': 6.0, 'default': 2.5, 'step': 0.01, 'is_int': False},
1707
+ 'BandgapCrystal': {'min': 0.5, 'max': 7.0, 'default': 2.5, 'step': 0.01, 'is_int': False},
1708
+ 'GasPerma': {'min': 0.0, 'max': 1000.0, 'default': 2.5, 'step': 0.1, 'is_int': False},
1709
+ 'Refractive': {'min': 1.2, 'max': 2.0, 'default': 1.5, 'step': 0.01, 'is_int': False},
1710
+
1711
+ 'LOI': {'min': 15.0, 'max': 100.0, 'default': 28.0, 'step': 0.5, 'is_int': False},
1712
+
1713
+ # Çözünürlük (Hildebrand): 7-10 arası apolar çözücüler, 12+ polar
1714
+ 'Solubility': {'min': 5.0, 'max': 20.0, 'default': 9.5, 'step': 0.1, 'is_int': False},
1715
+
1716
+ # Isıl İletkenlik: Polimerler genelde 0.1-0.5 arasıdır (yalıtkan)
1717
+ 'ThermalCond': {'min': 0.0, 'max': 1.0, 'default': 0.2, 'step': 0.01, 'is_int': False},
1718
+
1719
+ # CTE (Genleşme): Düşük olması (boyutsal kararlılık) istenir.
1720
+ 'CTE': {'min': 0.0, 'max': 300.0, 'default': 60.0, 'step': 5.0, 'is_int': False}
1721
+ }
1722
+
1723
+ # Her seçili özellik için senkron slider + number_input ekle
1724
+ for prop in active_props:
1725
+ if prop in ranges:
1726
+ r = ranges[prop]
1727
+ label = prop
1728
+ # Kullanıcıya daha dostça etiket gösterimi
1729
+ if prop == 'Tg': label = 'Hedef Tg (°C)'
1730
+ elif prop == 'Td': label = 'Hedef Td (°C)'
1731
+ elif prop == 'Tm': label = 'Hedef Tm (°C)'
1732
+ elif prop == 'EPS': label = 'Hedef EPS'
1733
+ elif prop == 'BandgapBulk': label = 'Hedef BandgapBulk (eV)'
1734
+ elif prop == 'BandgapChain': label = 'Hedef BandgapChain (eV)'
1735
+ elif prop == 'BandgapCrystal': label = 'Hedef BandgapCrystal (eV)'
1736
+ elif prop == 'GasPerma': label = 'Hedef GasPerma'
1737
+ elif prop == 'Refractive': label = 'Hedef Refractive Index'
1738
+
1739
+ val = add_synced_input(prop, label, r['min'], r['max'], r['default'], r['step'], is_int=r['is_int'])
1740
+ targets[prop] = val
1741
+ else:
1742
+ # Eğer ranges sözlüğünde yoksa varsayılan number_input (güncelleme kolaylığı için)
1743
+ targets[prop] = st.sidebar.number_input(f"Hedef {prop}:", value=0.0)
1744
+
1745
+ # 3. GA Parametreleri
1746
+ generations = st.sidebar.slider("Evrim Nesli Sayısı", 10, 300, 10)
1747
+
1748
+ # Başlangıç popülasyonu (Gerçek verinizi buraya koyun)
1749
+ initial_selfies, reference_smiles = get_initial_population()
1750
+ # Sidebar'ın en altına ekleyebilirsiniz
1751
+ st.sidebar.divider()
1752
+ st.sidebar.markdown("### 🤖 AI Asistan Ayarları")
1753
+ api_key = st.sidebar.text_input("Google Gemini API Key", type="password", help="AI yorumu almak için https://aistudio.google.com/app/apikey adresinden ücretsiz anahtar alabilirsiniz.")
1754
+ # --- BUTON VE HESAPLAMA KISMI ---
1755
+ if st.sidebar.button("🚀 Hedefi Ara", type="primary"):
1756
+
1757
+ if not initial_selfies:
1758
+ st.error("Başlangıç popülasyonu boş veya geçersiz.")
1759
+ st.stop()
1760
+
1761
+ with st.spinner(f'Genetik Algoritma Çalışıyor... Hedefler: {", ".join(active_props)}'):
1762
+ # Hesaplama yapılıyor
1763
+ best_poly_data, history = run_single_objective_flow(models, generations, targets, active_props, initial_selfies, ranges)
1764
+
1765
+ # SONUÇLARI HAFIZAYA (SESSION STATE) KAYDET
1766
+ if best_poly_data:
1767
+ st.session_state['ga_results'] = best_poly_data
1768
+ st.session_state['ga_history'] = history
1769
+ st.session_state['ga_targets'] = targets # O anki hedefleri de sakla
1770
+ st.session_state['ga_active_props'] = active_props # O anki aktif özellikleri de sakla
1771
+
1772
+ # --- SONUÇLARI GÖSTERME KISMI (BUTON BLOĞUNUN DIŞINDA) ---
1773
+
1774
+ # Hafızada sonuç varsa ekrana bas (Sayfa yenilense de burası çalışır)
1775
+ if 'ga_results' in st.session_state:
1776
+
1777
+ # Verileri hafızadan geri çağır
1778
+ best_poly_data = st.session_state['ga_results']
1779
+ history = st.session_state['ga_history']
1780
+ saved_targets = st.session_state['ga_targets']
1781
+ saved_active_props = st.session_state['ga_active_props']
1782
+
1783
+ preds = best_poly_data['preds']
1784
+
1785
+ st.success("✅ Optimizasyon Başarıyla Tamamlandı! (Sonuçlar Hafızada)")
1786
+
1787
+ # 4 SEKME YAPISI
1788
+ tab1, tab2, tab3, tab4, tab5, tab6 = st.tabs(["📊 Genel Bakış", "🧬 Yapısal Analiz", "📈 Evrim Geçmişi", "💾 Raporlama", "🤖 AI Analizi", "🧪 Retrosentez"])
1789
+ # --- TAB 1: ÖZET ---
1790
+ with tab1:
1791
+ col_main, col_score, col_green = st.columns([2, 1, 1])
1792
+
1793
+ with col_main:
1794
+ st.markdown(f"### 🏆 Toplam Hata: **{best_poly_data['total_error']:.4f}**")
1795
+
1796
+ with col_score:
1797
+ sa = get_sa_score_local(best_poly_data['smiles'])
1798
+ st.metric("Sentez Zorluğu (SA)", f"{sa:.2f}", help="1 (Kolay) - 10 (Zor)")
1799
+
1800
+ with col_green:
1801
+ # Yeni Yeşil Kimya Skorunu Hesapla
1802
+ g_score, g_note, g_color = calculate_green_score(best_poly_data['smiles'])
1803
+
1804
+ # Özel renkli metrik gösterimi (HTML ile)
1805
+ st.markdown(f"""
1806
+ <div style="background-color:{g_color}20; border: 1px solid {g_color}; border-radius: 5px; padding: 5px; text-align: center;">
1807
+ <strong style="color:{g_color}; font-size: 0.8rem;">🌱 Yeşil Skor</strong><br>
1808
+ <span style="font-size: 1.5rem; font-weight: bold; color:{g_color};">{g_score:.1f}/10</span>
1809
+ </div>
1810
+ """, unsafe_allow_html=True)
1811
+
1812
+ # Notları altına küçük yazıyla ekle
1813
+ if g_note:
1814
+ st.caption(f"**Çevresel Analiz:** {g_note}")
1815
+
1816
+ st.divider()
1817
+ if 'Solubility' in preds:
1818
+ sol_val = preds['Solubility']
1819
+ solvents, partials = get_soluble_solvents(sol_val)
1820
+
1821
+ st.markdown("### 🧪 Tahmini Çözünürlük Analizi")
1822
+ c1, c2 = st.columns(2)
1823
+
1824
+ with c1:
1825
+ st.info(f"**Çözünmesi Beklenenler:**")
1826
+ if solvents:
1827
+ # Yeşil etiketlerle göster
1828
+ for s in solvents:
1829
+ st.markdown(f"- ✅ {s}")
1830
+ else:
1831
+ st.warning("Bu polimer çok dirençli görünüyor (veya çok özel bir çözücü gerektiriyor).")
1832
+
1833
+ with c2:
1834
+ st.warning(f"**Şişme / Zor Çözünme Beklenenler:**")
1835
+ if partials:
1836
+ for s in partials:
1837
+ st.markdown(f"- ⚠️ {s}")
1838
+ else:
1839
+ st.write("-")
1840
+
1841
+ st.caption(f"*Analiz, 'Benzer Benzeri Çözer' ilkesine göre Polimer (δ={sol_val:.1f}) ve Çözücü arasındaki Hildebrand farkına dayanır.*")
1842
+ cols = st.columns(3)
1843
+ for idx, prop in enumerate(ALL_PROPS):
1844
+ with cols[idx % 3]:
1845
+ is_active = prop in saved_active_props
1846
+ target_val = saved_targets.get(prop, '-')
1847
+ target_text = f"Hedef: {target_val}" if is_active else "Takip Dışı"
1848
+ border_color = "#2ecc71" if is_active else "#95a5a6"
1849
+ pred_value = preds[prop]
1850
+
1851
+ st.markdown(f"""
1852
+ <div class="metric-card" style="border-left: 5px solid {border_color};">
1853
+ <small>{prop}</small><br>
1854
+ <h3 style="margin:0; padding:0;">{pred_value:.2f}</h3>
1855
+ <small style="opacity:0.7">{target_text}</small>
1856
+ </div>
1857
+ """, unsafe_allow_html=True)
1858
+ st.divider()
1859
+ st.subheader("🎯 Hedef Uyumluluk Analizi")
1860
+ if len(saved_active_props) >= 3:
1861
+ fig = create_radar_chart(preds, saved_targets, saved_active_props, ranges)
1862
+ st.plotly_chart(fig, use_container_width=True)
1863
+ else:
1864
+ st.info("Radar grafiği için en az 3 özellik (Örn: Tg, LOI, CTE) seçmelisiniz.")
1865
+ # Az özellik varsa bar chart gösterelim
1866
+ st.progress(100) # Görsel dolgu
1867
+ # --- TAB 2: GÖRSELLİK ---
1868
+ with tab2:
1869
+ col_2d, col_3d = st.columns(2)
1870
+ with col_2d:
1871
+ st.subheader("2D Yapı (Teknik Çizim)")
1872
+ img = draw_2d_molecule(best_poly_data['smiles'])
1873
+ if img:
1874
+ st.image(img, width=400)
1875
+ st.caption("SMILES Kodu:")
1876
+ st.code(best_poly_data['smiles'], language="text")
1877
+
1878
+ with col_3d:
1879
+ st.subheader("3D Konformasyon")
1880
+ view, reason = make_3d_view_with_reason(best_poly_data["smiles"])
1881
+ if view:
1882
+ showmol(view, height=400, width=400)
1883
+ else:
1884
+ st.warning(f"3D Model oluşturulamadı: {reason}")
1885
+
1886
+ is_avail, cid, name = check_pubchem_availability(best_poly_data['smiles'])
1887
+ if is_avail:
1888
+ st.info(f"💡 Bu molekül PubChem'de kayıtlı: **{name}** (CID: {cid})")
1889
+ st.divider()
1890
+ # --- YENİ: ÖZGÜNLÜK / NOVELTY ANALİZİ ---
1891
+ st.subheader("🔍 Özgünlük Analizi (Novelty Search)")
1892
+
1893
+ # reference_smiles değişkenini get_initial_population'dan almıştık
1894
+ similarity_score, similar_smi = calculate_novelty_optimized(best_poly_data['smiles'], reference_smiles)
1895
+
1896
+ c1, c2 = st.columns([1, 3])
1897
+
1898
+ with c1:
1899
+ # Benzerlik Skoru
1900
+ st.metric("Eğitim Setine Benzerlik", f"%{similarity_score*100:.1f}")
1901
+
1902
+ with c2:
1903
+ # Yorum
1904
+ if similarity_score > 0.99:
1905
+ st.error(f"⚠️ **Kopya:** Yapay zeka eğitim setindeki bir veriyi ezberlemiş.")
1906
+ st.code(f"Benzer Kayıt: {similar_smi}")
1907
+ elif similarity_score > 0.85:
1908
+ st.warning(f"ℹ️ **Türev:** Eğitim setindeki bir yapıya çok benziyor.")
1909
+ with st.expander("Benzer Yapıyı Gör"):
1910
+ st.code(similar_smi)
1911
+ else:
1912
+ st.success(f"🌟 **KEŞİF:** Bu yapı eğitim setinde YOK! Tamamen özgün bir tasarım.")
1913
+ st.caption(f"En yakın benzerlik sadece %{similarity_score*100:.1f} oranında.")
1914
+
1915
+ st.progress(similarity_score)
1916
+ st.caption("*Benzerlik, Tanimoto İndeksi (Morgan Fingerprints) kullanılarak hesaplanmıştır.*")
1917
+
1918
+ # --- TAB 3: GRAFİK ---
1919
+ # --- TAB 3: PERFORMANS ANALİZİ ---
1920
+ with tab3:
1921
+ st.subheader("📈 Genetik Algoritma Performans Raporu")
1922
+
1923
+ if 'best_fitness' in history and len(history['best_fitness']) > 0:
1924
+ # Matplotlib ile Profesyonel Çizim
1925
+ fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8))
1926
+
1927
+ # X Ekseni
1928
+ gens = range(len(history['best_fitness']))
1929
+
1930
+ # Grafik 1: Yakınsama (Convergence)
1931
+ ax1.plot(gens, history['best_fitness'], label='En İyi Birey (Best)', color='green', linewidth=2)
1932
+ ax1.plot(gens, history['avg_fitness'], label='Popülasyon Ortalaması (Avg)', color='blue', linestyle='--', alpha=0.7)
1933
+ ax1.set_ylabel('Hata Skoru')
1934
+ ax1.set_title('Yakınsama Analizi (Convergence)', fontweight='bold')
1935
+ ax1.legend()
1936
+ ax1.grid(True, which='both', linestyle='--', alpha=0.5)
1937
+
1938
+ # Grafik 2: Çeşitlilik (Diversity)
1939
+ ax2.plot(gens, history['diversity'], label='Standart Sapma (Diversity)', color='red', linewidth=2)
1940
+ ax2.fill_between(gens, history['diversity'], color='red', alpha=0.1)
1941
+ ax2.set_ylabel('Çeşitlilik (Std Dev)')
1942
+ ax2.set_xlabel('Jenerasyon')
1943
+ ax2.set_title('Popülasyon Çeşitliliği (Diversity)', fontweight='bold')
1944
+ ax2.legend()
1945
+ ax2.grid(True, which='both', linestyle='--', alpha=0.5)
1946
+
1947
+ plt.tight_layout()
1948
+ st.pyplot(fig)
1949
+
1950
+ # Yorumlama Kılavuzu
1951
+ st.info("""
1952
+ **Bu Grafikler Nasıl Okunur?**
1953
+ * **Yakınsama (Üst):** Yeşil çizgi sürekli düşmeli ve bir noktada yataylaşmalıdır (Plateau). Mavi çizgi yeşile çok yaklaşırsa popülasyon "öğrenmiş" demektir.
1954
+ * **Çeşitlilik (Alt):** Kırmızı çizginin sıfıra çok hızlı düşmemesi gerekir. Sıfıra düşerse model "Erken Yakınsama (Premature Convergence)" tuzağına düşmüştür; yani arama uzayını yeterince taramadan bir sonuca saplanmıştır.
1955
+ """)
1956
+ else:
1957
+ st.warning("Henüz grafik çizilecek veri yok.")
1958
+ # --- TAB 3: BENCHMARK VE PERFORMANS ---
1959
+ with tab3:
1960
+ st.header("🏆 Performans Kıyaslama (Benchmark)")
1961
+ st.markdown("Modelin başarısını kanıtlamak için onu 'Rastgele Arama' ile yarıştırın.")
1962
+
1963
+ # Eğer GA sonuçları varsa
1964
+ if 'ga_history' in st.session_state and 'best_fitness' in st.session_state['ga_history']:
1965
+ history = st.session_state['ga_history']
1966
+ ga_best_curve = history['best_fitness']
1967
+
1968
+ # Benchmark Butonu
1969
+ if st.button("🏁 Rastgele Arama ile Kıyasla (Benchmark Başlat)"):
1970
+ with st.spinner("Rastgele Arama yapılıyor... Bu işlem GA kadar sürebilir."):
1971
+ # GA'nın toplam bütçesini hesapla (Jenerasyon x 100 birey)
1972
+ generations_run = len(ga_best_curve)
1973
+ pop_size = 100 # Kodunuzda sabit 100'dü
1974
+ total_evals = generations_run * pop_size
1975
+
1976
+ # Benchmark'ı çalıştır
1977
+ random_curve = run_random_benchmark(
1978
+ models, saved_targets, saved_active_props,
1979
+ initial_selfies, ranges,
1980
+ total_budget=total_evals,
1981
+ batch_size=pop_size
1982
+ )
1983
+
1984
+ # Sonucu Session State'e kaydet (Sayfa yenilenince gitmesin)
1985
+ st.session_state['random_curve'] = random_curve
1986
+ st.success("Benchmark Tamamlandı!")
1987
+
1988
+ # --- GRAFİK ÇİZİMİ ---
1989
+ fig, ax = plt.subplots(figsize=(10, 6))
1990
+
1991
+ # 1. GA Çizgisi (Yeşil)
1992
+ ax.plot(ga_best_curve, label='Genetik Algoritma (Sizin Modeliniz)', color='green', linewidth=2.5)
1993
+
1994
+ # 2. Random Search Çizgisi (Gri/Siyah) - Varsa çiz
1995
+ if 'random_curve' in st.session_state:
1996
+ # Uzunlukları eşitle (Bazen 1 eksik/fazla olabilir)
1997
+ min_len = min(len(ga_best_curve), len(st.session_state['random_curve']))
1998
+ r_curve = st.session_state['random_curve'][:min_len]
1999
+ g_curve = ga_best_curve[:min_len]
2000
+
2001
+ ax.plot(r_curve, label='Rastgele Arama (Random Search)', color='gray', linestyle='--', linewidth=2)
2002
+
2003
+ # Farkı hesapla (Son jenerasyon)
2004
+ diff = r_curve[-1] - g_curve[-1]
2005
+ st.caption(f"**Sonuç:** GA modeliniz, rastgele aramadan **{diff:.2f} puan** daha iyi performans gösterdi.")
2006
+
2007
+ ax.set_title("Zeka Testi: GA vs Şans", fontweight='bold')
2008
+ ax.set_xlabel("Jenerasyon (Her adımda 100 yeni deneme)")
2009
+ ax.set_ylabel("Hata Skoru (Düşük İyidir)")
2010
+ ax.legend()
2011
+ ax.grid(True, linestyle='--', alpha=0.5)
2012
+
2013
+ st.pyplot(fig)
2014
+
2015
+ st.info("""
2016
+ **Grafik Nasıl Yorumlanır?**
2017
+ * **Yeşil Çizgi:** Hızlıca aşağı iniyorsa, modeliniz 'öğreniyor' demektir.
2018
+ * **Gri Çizgi:** Genelde daha yukarıda ve düz kalır.
2019
+ * **Fark:** İki çizgi arasındaki boşluk, Yapay Zekanızın kattığı değerdir.
2020
+ """)
2021
+
2022
+ else:
2023
+ st.warning("Önce 'Hedefi Ara' butonuna basarak GA'yı çalıştırın, sonra kıyaslama yapabilirsiniz.")
2024
+ st.divider()
2025
+ st.header("🎲 Büyük Stres Testi (Mass Random Testing)")
2026
+ st.markdown("""
2027
+ Modelin **genelleştirme yeteneğini** ölçmek için rastgele hedeflerle çoklu deneme yapın.
2028
+ * Her denemede farklı özellikler ve farklı hedef değerler seçilir.
2029
+ * Modelin "kolay" ve "zor" hedeflere tepkisi ölçülür.
2030
+ """)
2031
+
2032
+ col_mass_input, col_mass_btn = st.columns([1, 2])
2033
+ with col_mass_input:
2034
+ mass_trials = st.number_input("Test Sayısı", min_value=10, max_value=500, value=100, step=10)
2035
+
2036
+ if col_mass_btn.button("🔥 100+ Rastgele Testi Başlat"):
2037
+ with st.spinner("Model zorlu bir sınava giriyor... Kahvenizi alın, bu biraz sürebilir."):
2038
+ df_results = run_mass_random_test(models, generations, initial_selfies, ranges, num_trials=mass_trials)
2039
+
2040
+ # --- SONUÇ ANALİZİ ---
2041
+ st.subheader("📊 Test Sonuçları")
2042
+
2043
+ # 1. Özet Metrikler
2044
+ avg_error = df_results["Final Hata Skoru"].mean()
2045
+ success_count = df_results[df_results["Final Hata Skoru"] < 5.0].shape[0]
2046
+ success_rate = (success_count / mass_trials) * 100
2047
+
2048
+ m1, m2, m3 = st.columns(3)
2049
+ m1.metric("Ortalama Hata", f"{avg_error:.2f}")
2050
+ m2.metric("Başarı Oranı (Hata < 5.0)", f"%{success_rate:.1f}")
2051
+ m3.metric("En Zorlu Senaryo Hatası", f"{df_results['Final Hata Skoru'].max():.2f}")
2052
+
2053
+ # 2. Histogram (Hata Dağılımı)
2054
+ fig_hist, ax_hist = plt.subplots(figsize=(10, 5))
2055
+ ax_hist.hist(df_results["Final Hata Skoru"], bins=20, color='#3498db', edgecolor='black', alpha=0.7)
2056
+ ax_hist.set_title("Hata Skorlarının Dağılımı (Histogram)")
2057
+ ax_hist.set_xlabel("Hata Skoru (Sola yığılma iyidir)")
2058
+ ax_hist.set_ylabel("Deneme Sayısı")
2059
+ ax_hist.axvline(avg_error, color='red', linestyle='dashed', linewidth=1, label=f'Ortalama: {avg_error:.2f}')
2060
+ ax_hist.legend()
2061
+ st.pyplot(fig_hist)
2062
+
2063
+ # 3. Scatter Plot (Zorluk vs Hata)
2064
+ # Hedef sayısı arttıkça hata artıyor mu?
2065
+ fig_sc, ax_sc = plt.subplots(figsize=(10, 5))
2066
+ ax_sc.scatter(df_results["Hedef Sayısı"], df_results["Final Hata Skoru"], alpha=0.6, c=df_results["Final Hata Skoru"], cmap='viridis')
2067
+ ax_sc.set_title("Hedef Sayısı vs. Başarı")
2068
+ ax_sc.set_xlabel("Aktif Hedef Sayısı (Zorluk)")
2069
+ ax_sc.set_ylabel("Hata Skoru")
2070
+ ax_sc.grid(True, alpha=0.3)
2071
+ st.pyplot(fig_sc)
2072
+
2073
+ # 4. Detaylı Tablo
2074
+ with st.expander("📄 Tüm Test Verilerini Gör"):
2075
+ st.dataframe(df_results)
2076
+
2077
+ # --- TAB 4: İNDİRME ---
2078
+ # --- TAB 4: RAPORLAMA ve İNDİRME ---
2079
+ with tab4:
2080
+ st.header("💾 Raporlama Merkezi")
2081
+ st.markdown("Proje verilerini CSV veya detaylı PDF raporu olarak dışa aktarabilirsiniz.")
2082
+
2083
+ c1, c2 = st.columns(2)
2084
+
2085
+ # --- CSV İNDİRME KISMI (Mevcut) ---
2086
+ # ... (Buradaki CSV kodlarınız aynen kalabilir) ...
2087
+ export_dict = {
2088
+ "SMILES": best_poly_data['smiles'],
2089
+ "Toplam Hata": best_poly_data['total_error'],
2090
+ "SA Score": get_sa_score_local(best_poly_data['smiles'])
2091
+ }
2092
+ export_dict.update(preds)
2093
+ df_best = pd.DataFrame([export_dict])
2094
+ csv_best = df_best.to_csv(index=False).encode('utf-8')
2095
+
2096
+ with c1:
2097
+ st.download_button(
2098
+ label="📊 Veri Setini İndir (.csv)",
2099
+ data=csv_best,
2100
+ file_name="polimer_data.csv",
2101
+ mime="text/csv"
2102
+ )
2103
+
2104
+ st.divider()
2105
+
2106
+ # --- PDF RAPOR OLUŞTURMA KISMI (Yeni Yeri) ---
2107
+ st.subheader("📄 Kapsamlı PDF Raporu")
2108
+ st.info("Bu rapor; tüm tahminleri, molekül yapısını, AI yorumlarını ve varsa sentez planını içerir.")
2109
+
2110
+ # Verileri Session State'ten Topla
2111
+
2112
+ # 1. AI Yorumu (Tab 5'ten)
2113
+ gen_ai_analysis = st.session_state.get('ai_analysis', "Genel AI analizi yapilmadi.")
2114
+
2115
+ # 2. Retrosentez Bilgisi (Tab 6'dan)
2116
+ # Eğer kullanıcı Tab 6'ya hiç gitmediyse, bu veriler eksik olabilir.
2117
+ manual_retro = st.session_state.get('retro_manual_text', "Otomatik ayristirma verisi yok (Retrosentez sekmesini ziyaret edin).")
2118
+ ai_retro = st.session_state.get('ai_retro_text', "AI sentez recetesi olusturulmadi.")
2119
+
2120
+ full_retro_info = manual_retro + "\n\n--- AI Sentez Notlari ---\n" + ai_retro
2121
+
2122
+ if st.button("🚀 PDF Raporu Oluştur", type="primary", use_container_width=True):
2123
+ with st.spinner("Rapor derleniyor..."):
2124
+ pdf_data = create_pdf_report(
2125
+ best_poly_data,
2126
+ saved_targets,
2127
+ saved_active_props,
2128
+ gen_ai_analysis,
2129
+ full_retro_info
2130
+ )
2131
+
2132
+ st.success("Rapor hazır!")
2133
+ st.download_button(
2134
+ label="📥 PDF Dosyasını İndir",
2135
+ data=pdf_data,
2136
+ file_name="PolimerX_Final_Raporu.pdf",
2137
+ mime="application/pdf",
2138
+ use_container_width=True
2139
+ )
2140
+ with tab5:
2141
+ st.subheader("🧠 Yapay Zeka Uzman Görüşü")
2142
+
2143
+ if not api_key:
2144
+ st.info("💡 Bu polimer hakkında detaylı kimyasal yorum almak için sol menüden **Google Gemini API Key** girmelisiniz.")
2145
+ st.markdown("[👉 Ücretsiz API Key Almak İçin Tıkla](https://aistudio.google.com/app/apikey)")
2146
+ else:
2147
+ # Butonla tetikleyelim ki her sayfa yenilemede kredi harcamasın
2148
+ if st.button("✨ Polimeri Analiz Et", type="primary"):
2149
+ analysis_result = get_ai_interpretation(
2150
+ api_key,
2151
+ best_poly_data['smiles'],
2152
+ best_poly_data['preds'],
2153
+ saved_targets,
2154
+ saved_active_props
2155
+ )
2156
+ st.markdown(analysis_result)
2157
+
2158
+ # Analizi de kaydetmek isterseniz session state'e atabilirsiniz
2159
+ st.session_state['ai_analysis'] = analysis_result
2160
+
2161
+ # Eğer daha önce analiz yapıldıysa hafızadan göster
2162
+ elif 'ai_analysis' in st.session_state:
2163
+ st.markdown(st.session_state['ai_analysis'])
2164
+ # --- TAB 6: RETROSENTEZ ve RAPORLAMA ---
2165
+ # --- TAB 6: RETROSENTEZ (Sadece Analiz) ---
2166
+ with tab6:
2167
+ st.header("🧪 Retrosentez Analizi")
2168
+
2169
+ target_smiles = best_poly_data['smiles']
2170
+
2171
+ # --- 1. OTOMATİK AYRIŞTIRMA ---
2172
+ st.subheader("1. Yapısal Ayrıştırma")
2173
+ retro_results = decompose_polymer(target_smiles)
2174
+
2175
+ monomer_info_text = "Otomatik analiz yapilmadi." # Varsayılan
2176
+
2177
+ if retro_results:
2178
+ best_route = retro_results[0]
2179
+
2180
+ # Metni oluştur
2181
+ monomer_info_text = f"Yontem: {best_route['type']}\nMekanizma: {best_route['mechanism']}\n"
2182
+
2183
+ st.info(f"**Algılanan Sentez Türü:** {best_route['type']}")
2184
+ st.write(f"**Mekanizma:** {best_route['mechanism']}")
2185
+
2186
+ st.markdown("**Olası Başlangıç Monomerleri:**")
2187
+ img_retro = draw_retrosynthesis_grid(best_route['monomers'])
2188
+ if img_retro: st.image(img_retro)
2189
+
2190
+ # Ticari Kontrol
2191
+ st.markdown("#### 🛒 Ticari Bulunabilirlik")
2192
+ found_monomers = []
2193
+ for i, m in enumerate(best_route['monomers']):
2194
+ col_code, col_check = st.columns([3, 1])
2195
+ with col_code:
2196
+ st.code(f"Monomer {i+1}: {m}")
2197
+ with col_check:
2198
+ if st.button(f"🔍 Kontrol #{i+1}", key=f"chk_{i}"):
2199
+ is_avail, cid, name = check_commercial_availability(m)
2200
+ if is_avail:
2201
+ st.success(f"Var: {name}")
2202
+ found_monomers.append(name)
2203
+ else:
2204
+ st.error("Ticari kayit yok")
2205
+
2206
+ if found_monomers:
2207
+ monomer_info_text += f"\nTicari Kaydi Olanlar: {', '.join(found_monomers)}"
2208
+ else:
2209
+ monomer_info_text += "\nTicari kayit kontrolu yapilmadi veya bulunamadi."
2210
+
2211
+ else:
2212
+ st.warning("Yapısal ayrıştırma başarısız.")
2213
+ monomer_info_text = "Yapısal ayrıştırma başarısız."
2214
+
2215
+ # --- VERİYİ KAYDET (Tab 4 için) ---
2216
+ st.session_state['retro_manual_text'] = monomer_info_text
2217
+
2218
+ st.divider()
2219
+
2220
+ # --- 2. AI SENTEZ PLANI ---
2221
+ st.subheader("2. AI Sentez Reçetesi")
2222
+
2223
+ if api_key and st.button("⚗️ Sentez Rotasını Oluştur (AI)", type="primary"):
2224
+ ai_retro_text = get_ai_retrosynthesis_guide(api_key, target_smiles, str(retro_results))
2225
+ st.markdown(ai_retro_text)
2226
+ st.session_state['ai_retro_text'] = ai_retro_text
2227
+
2228
+ elif 'ai_retro_text' in st.session_state:
2229
+ st.markdown(st.session_state['ai_retro_text'])
2230
+ # --- MEVCUT TAB 6 KODUNUN DEVAMI ---
2231
+
2232
+ st.divider()
2233
+
2234
+ # --- 2. YEREL MODEL TAHMİNİ (GEMINI YERİNE) ---
2235
+ st.subheader("2. T5-Model Tahmini (Machine Learning)")
2236
+ st.caption("Eğittiğimiz model, moleküler yapıyı analiz ederek monomerleri tahmin ediyor.")
2237
+
2238
+ if st.button("🧠 Monomerleri Tahmin Et", type="primary"):
2239
+ with st.spinner("Yapay zeka düşünüyor..."):
2240
+ # Tahmin Fonksiyonunu Çağır
2241
+ prediction = predict_monomers_local(best_poly_data['smiles'])
2242
+
2243
+ # Sonucu Göster
2244
+ st.success("Tahmin Başarılı!")
2245
+
2246
+ st.markdown(f"""
2247
+ <div style="background-color:#e8f5e9; padding:15px; border-radius:10px; border:1px solid #4CAF50;">
2248
+ <h4 style="color:#2e7d32; margin:0;">🧪 Önerilen Monomerler:</h4>
2249
+ <code style="font-size:1.1em; color:#1b5e20; background-color:#e8f5e9;">{prediction}</code>
2250
+ </div>
2251
+ """, unsafe_allow_html=True)
2252
+ print("Predicted monomers:", prediction)
2253
+ # Görselleştirme
2254
+ monomers_list = prediction.split(' . ') # Veri setinde " . " ile ayırmıştık
2255
+ img_retro = draw_retrosynthesis_grid(monomers_list)
2256
+ if img_retro:
2257
+ st.image(img_retro, caption="Modelin Önerdiği Yapı Taşları")
2258
+
2259
+ # Session State'e kaydet (PDF raporu için)
2260
+ st.session_state['retro_manual_text'] = f"AI Tahmini: {prediction}"
config.json ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "T5ForConditionalGeneration"
4
+ ],
5
+ "classifier_dropout": 0.0,
6
+ "d_ff": 2048,
7
+ "d_kv": 64,
8
+ "d_model": 512,
9
+ "decoder_start_token_id": 0,
10
+ "dense_act_fn": "relu",
11
+ "dropout_rate": 0.1,
12
+ "dtype": "float32",
13
+ "eos_token_id": 1,
14
+ "feed_forward_proj": "relu",
15
+ "initializer_factor": 1.0,
16
+ "is_encoder_decoder": true,
17
+ "is_gated_act": false,
18
+ "layer_norm_epsilon": 1e-06,
19
+ "model_type": "t5",
20
+ "n_positions": 512,
21
+ "num_decoder_layers": 6,
22
+ "num_heads": 8,
23
+ "num_layers": 6,
24
+ "output_past": true,
25
+ "pad_token_id": 0,
26
+ "relative_attention_max_distance": 128,
27
+ "relative_attention_num_buckets": 32,
28
+ "task_specific_params": {
29
+ "summarization": {
30
+ "early_stopping": true,
31
+ "length_penalty": 2.0,
32
+ "max_length": 200,
33
+ "min_length": 30,
34
+ "no_repeat_ngram_size": 3,
35
+ "num_beams": 4,
36
+ "prefix": "summarize: "
37
+ },
38
+ "translation_en_to_de": {
39
+ "early_stopping": true,
40
+ "max_length": 300,
41
+ "num_beams": 4,
42
+ "prefix": "translate English to German: "
43
+ },
44
+ "translation_en_to_fr": {
45
+ "early_stopping": true,
46
+ "max_length": 300,
47
+ "num_beams": 4,
48
+ "prefix": "translate English to French: "
49
+ },
50
+ "translation_en_to_ro": {
51
+ "early_stopping": true,
52
+ "max_length": 300,
53
+ "num_beams": 4,
54
+ "prefix": "translate English to Romanian: "
55
+ }
56
+ },
57
+ "transformers_version": "4.57.3",
58
+ "use_cache": true,
59
+ "vocab_size": 32128
60
+ }
fpscores.pkl.gz ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:10dcef9340c873e7b987924461b0af5365eb8dd96be607203debe8ddf80c1e73
3
+ size 3848394
generation_config.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "decoder_start_token_id": 0,
4
+ "eos_token_id": [
5
+ 1
6
+ ],
7
+ "pad_token_id": 0,
8
+ "transformers_version": "4.57.3"
9
+ }
lgbm_gas_pipeline.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:25cbe38babbee4527c033340f324f31ff70363faec07370b83747bc9c63e7350
3
+ size 1932028
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cf17ce234cda524e4b9d0d921ea7693bfcd243d5d6602a7ccad8968b8ae89d23
3
+ size 242041896
polimerx_critic_v2_sanitized.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1cbed399cb5dfe36ba48b81637f5ad5c5a6b0c2a25942abcdf232b8d09a7678d
3
+ size 2006300
requirements.txt CHANGED
Binary files a/requirements.txt and b/requirements.txt differ
 
rf_eps.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:37f6d461ac42dd294f84df18bc56fd7314d3abc145d3c05886d7a6ab03c3272c
3
+ size 2735137
rf_refractive_index.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a1341740aeab83726a919e4255b5c8221b95d49a845700f6c439974de0a89141
3
+ size 4958065
sascorer.py ADDED
@@ -0,0 +1,192 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # calculation of synthetic accessibility score as described in:
3
+ #
4
+ # Estimation of Synthetic Accessibility Score of Drug-like Molecules based on Molecular Complexity and Fragment Contributions
5
+ # Peter Ertl and Ansgar Schuffenhauer
6
+ # Journal of Cheminformatics 1:8 (2009)
7
+ # http://www.jcheminf.com/content/1/1/8
8
+ #
9
+ # several small modifications to the original paper are included
10
+ # particularly slightly different formula for marocyclic penalty
11
+ # and taking into account also molecule symmetry (fingerprint density)
12
+ #
13
+ # for a set of 10k diverse molecules the agreement between the original method
14
+ # as implemented in PipelinePilot and this implementation is r2 = 0.97
15
+ #
16
+ # peter ertl & greg landrum, september 2013
17
+ #
18
+
19
+ from rdkit import Chem
20
+ from rdkit.Chem import rdFingerprintGenerator, rdMolDescriptors
21
+
22
+ import math
23
+ import pickle
24
+
25
+ import os.path as op
26
+
27
+ _fscores = None
28
+ mfpgen = rdFingerprintGenerator.GetMorganGenerator(radius=2)
29
+
30
+
31
+ def readFragmentScores(name="fpscores.pkl.gz"):
32
+ import gzip
33
+ global _fscores
34
+ # generate the full path filename:
35
+ if name == "fpscores.pkl.gz":
36
+ name = op.join(op.dirname(__file__), name)
37
+ data = pickle.load(gzip.open(name))
38
+ outDict = {}
39
+ for i in data:
40
+ for j in range(1, len(i)):
41
+ outDict[i[j]] = float(i[0])
42
+ _fscores = outDict
43
+
44
+
45
+ def numBridgeheadsAndSpiro(mol, ri=None):
46
+ nSpiro = rdMolDescriptors.CalcNumSpiroAtoms(mol)
47
+ nBridgehead = rdMolDescriptors.CalcNumBridgeheadAtoms(mol)
48
+ return nBridgehead, nSpiro
49
+
50
+
51
+ def calculateScore(m):
52
+
53
+ if not m.GetNumAtoms():
54
+ return None
55
+
56
+ if _fscores is None:
57
+ readFragmentScores()
58
+
59
+ # fragment score
60
+ sfp = mfpgen.GetSparseCountFingerprint(m)
61
+
62
+ score1 = 0.
63
+ nf = 0
64
+ nze = sfp.GetNonzeroElements()
65
+ for id, count in nze.items():
66
+ nf += count
67
+ score1 += _fscores.get(id, -4) * count
68
+
69
+ score1 /= nf
70
+
71
+ # features score
72
+ nAtoms = m.GetNumAtoms()
73
+ nChiralCenters = len(Chem.FindMolChiralCenters(m, includeUnassigned=True))
74
+ ri = m.GetRingInfo()
75
+ nBridgeheads, nSpiro = numBridgeheadsAndSpiro(m, ri)
76
+ nMacrocycles = 0
77
+ for x in ri.AtomRings():
78
+ if len(x) > 8:
79
+ nMacrocycles += 1
80
+
81
+ sizePenalty = nAtoms**1.005 - nAtoms
82
+ stereoPenalty = math.log10(nChiralCenters + 1)
83
+ spiroPenalty = math.log10(nSpiro + 1)
84
+ bridgePenalty = math.log10(nBridgeheads + 1)
85
+ macrocyclePenalty = 0.
86
+ # ---------------------------------------
87
+ # This differs from the paper, which defines:
88
+ # macrocyclePenalty = math.log10(nMacrocycles+1)
89
+ # This form generates better results when 2 or more macrocycles are present
90
+ if nMacrocycles > 0:
91
+ macrocyclePenalty = math.log10(2)
92
+
93
+ score2 = 0. - sizePenalty - stereoPenalty - spiroPenalty - bridgePenalty - macrocyclePenalty
94
+
95
+ # correction for the fingerprint density
96
+ # not in the original publication, added in version 1.1
97
+ # to make highly symmetrical molecules easier to synthetise
98
+ score3 = 0.
99
+ numBits = len(nze)
100
+ if nAtoms > numBits:
101
+ score3 = math.log(float(nAtoms) / numBits) * .5
102
+
103
+ sascore = score1 + score2 + score3
104
+
105
+ # need to transform "raw" value into scale between 1 and 10
106
+ min = -4.0
107
+ max = 2.5
108
+ sascore = 11. - (sascore - min + 1) / (max - min) * 9.
109
+
110
+ # smooth the 10-end
111
+ if sascore > 8.:
112
+ sascore = 8. + math.log(sascore + 1. - 9.)
113
+ if sascore > 10.:
114
+ sascore = 10.0
115
+ elif sascore < 1.:
116
+ sascore = 1.0
117
+
118
+ return sascore
119
+
120
+
121
+ def processMols(mols):
122
+ print('smiles\tName\tsa_score')
123
+ for i, m in enumerate(mols):
124
+ if m is None:
125
+ continue
126
+
127
+ s = calculateScore(m)
128
+
129
+ smiles = Chem.MolToSmiles(m)
130
+ if s is None:
131
+ print(f"{smiles}\t{m.GetProp('_Name')}\t{s}")
132
+ else:
133
+ print(f"{smiles}\t{m.GetProp('_Name')}\t{s:3f}")
134
+
135
+
136
+ if __name__ == '__main__':
137
+ import sys
138
+ import time
139
+
140
+ t1 = time.time()
141
+ if len(sys.argv) == 2:
142
+ readFragmentScores()
143
+ else:
144
+ readFragmentScores(sys.argv[2])
145
+ t2 = time.time()
146
+
147
+ molFile = sys.argv[1]
148
+ if molFile.endswith("smi"):
149
+ suppl = Chem.SmilesMolSupplier(molFile)
150
+ elif molFile.endswith("sdf"):
151
+ suppl = Chem.SDMolSupplier(molFile)
152
+ else:
153
+ print(f"Unrecognized file extension for {molFile}")
154
+ sys.exit()
155
+
156
+ t3 = time.time()
157
+ processMols(suppl)
158
+ t4 = time.time()
159
+
160
+ print('Reading took %.2f seconds. Calculating took %.2f seconds' % ((t2 - t1), (t4 - t3)),
161
+ file=sys.stderr)
162
+
163
+ #
164
+ # Copyright (c) 2013, Novartis Institutes for BioMedical Research Inc.
165
+ # All rights reserved.
166
+ #
167
+ # Redistribution and use in source and binary forms, with or without
168
+ # modification, are permitted provided that the following conditions are
169
+ # met:
170
+ #
171
+ # * Redistributions of source code must retain the above copyright
172
+ # notice, this list of conditions and the following disclaimer.
173
+ # * Redistributions in binary form must reproduce the above
174
+ # copyright notice, this list of conditions and the following
175
+ # disclaimer in the documentation and/or other materials provided
176
+ # with the distribution.
177
+ # * Neither the name of Novartis Institutes for BioMedical Research Inc.
178
+ # nor the names of its contributors may be used to endorse or promote
179
+ # products derived from this software without specific prior written permission.
180
+ #
181
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
182
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
183
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
184
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
185
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
186
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
187
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
188
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
189
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
190
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
191
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
192
+ #
special_tokens_map.json ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "additional_special_tokens": [
3
+ "<extra_id_0>",
4
+ "<extra_id_1>",
5
+ "<extra_id_2>",
6
+ "<extra_id_3>",
7
+ "<extra_id_4>",
8
+ "<extra_id_5>",
9
+ "<extra_id_6>",
10
+ "<extra_id_7>",
11
+ "<extra_id_8>",
12
+ "<extra_id_9>",
13
+ "<extra_id_10>",
14
+ "<extra_id_11>",
15
+ "<extra_id_12>",
16
+ "<extra_id_13>",
17
+ "<extra_id_14>",
18
+ "<extra_id_15>",
19
+ "<extra_id_16>",
20
+ "<extra_id_17>",
21
+ "<extra_id_18>",
22
+ "<extra_id_19>",
23
+ "<extra_id_20>",
24
+ "<extra_id_21>",
25
+ "<extra_id_22>",
26
+ "<extra_id_23>",
27
+ "<extra_id_24>",
28
+ "<extra_id_25>",
29
+ "<extra_id_26>",
30
+ "<extra_id_27>",
31
+ "<extra_id_28>",
32
+ "<extra_id_29>",
33
+ "<extra_id_30>",
34
+ "<extra_id_31>",
35
+ "<extra_id_32>",
36
+ "<extra_id_33>",
37
+ "<extra_id_34>",
38
+ "<extra_id_35>",
39
+ "<extra_id_36>",
40
+ "<extra_id_37>",
41
+ "<extra_id_38>",
42
+ "<extra_id_39>",
43
+ "<extra_id_40>",
44
+ "<extra_id_41>",
45
+ "<extra_id_42>",
46
+ "<extra_id_43>",
47
+ "<extra_id_44>",
48
+ "<extra_id_45>",
49
+ "<extra_id_46>",
50
+ "<extra_id_47>",
51
+ "<extra_id_48>",
52
+ "<extra_id_49>",
53
+ "<extra_id_50>",
54
+ "<extra_id_51>",
55
+ "<extra_id_52>",
56
+ "<extra_id_53>",
57
+ "<extra_id_54>",
58
+ "<extra_id_55>",
59
+ "<extra_id_56>",
60
+ "<extra_id_57>",
61
+ "<extra_id_58>",
62
+ "<extra_id_59>",
63
+ "<extra_id_60>",
64
+ "<extra_id_61>",
65
+ "<extra_id_62>",
66
+ "<extra_id_63>",
67
+ "<extra_id_64>",
68
+ "<extra_id_65>",
69
+ "<extra_id_66>",
70
+ "<extra_id_67>",
71
+ "<extra_id_68>",
72
+ "<extra_id_69>",
73
+ "<extra_id_70>",
74
+ "<extra_id_71>",
75
+ "<extra_id_72>",
76
+ "<extra_id_73>",
77
+ "<extra_id_74>",
78
+ "<extra_id_75>",
79
+ "<extra_id_76>",
80
+ "<extra_id_77>",
81
+ "<extra_id_78>",
82
+ "<extra_id_79>",
83
+ "<extra_id_80>",
84
+ "<extra_id_81>",
85
+ "<extra_id_82>",
86
+ "<extra_id_83>",
87
+ "<extra_id_84>",
88
+ "<extra_id_85>",
89
+ "<extra_id_86>",
90
+ "<extra_id_87>",
91
+ "<extra_id_88>",
92
+ "<extra_id_89>",
93
+ "<extra_id_90>",
94
+ "<extra_id_91>",
95
+ "<extra_id_92>",
96
+ "<extra_id_93>",
97
+ "<extra_id_94>",
98
+ "<extra_id_95>",
99
+ "<extra_id_96>",
100
+ "<extra_id_97>",
101
+ "<extra_id_98>",
102
+ "<extra_id_99>"
103
+ ],
104
+ "eos_token": {
105
+ "content": "</s>",
106
+ "lstrip": false,
107
+ "normalized": false,
108
+ "rstrip": false,
109
+ "single_word": false
110
+ },
111
+ "pad_token": {
112
+ "content": "<pad>",
113
+ "lstrip": false,
114
+ "normalized": false,
115
+ "rstrip": false,
116
+ "single_word": false
117
+ },
118
+ "unk_token": {
119
+ "content": "<unk>",
120
+ "lstrip": false,
121
+ "normalized": false,
122
+ "rstrip": false,
123
+ "single_word": false
124
+ }
125
+ }
spiece.model ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d60acb128cf7b7f2536e8f38a5b18a05535c9e14c7a355904270e15b0945ea86
3
+ size 791656
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,939 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": null,
3
+ "added_tokens_decoder": {
4
+ "0": {
5
+ "content": "<pad>",
6
+ "lstrip": false,
7
+ "normalized": false,
8
+ "rstrip": false,
9
+ "single_word": false,
10
+ "special": true
11
+ },
12
+ "1": {
13
+ "content": "</s>",
14
+ "lstrip": false,
15
+ "normalized": false,
16
+ "rstrip": false,
17
+ "single_word": false,
18
+ "special": true
19
+ },
20
+ "2": {
21
+ "content": "<unk>",
22
+ "lstrip": false,
23
+ "normalized": false,
24
+ "rstrip": false,
25
+ "single_word": false,
26
+ "special": true
27
+ },
28
+ "32000": {
29
+ "content": "<extra_id_99>",
30
+ "lstrip": false,
31
+ "normalized": false,
32
+ "rstrip": false,
33
+ "single_word": false,
34
+ "special": true
35
+ },
36
+ "32001": {
37
+ "content": "<extra_id_98>",
38
+ "lstrip": false,
39
+ "normalized": false,
40
+ "rstrip": false,
41
+ "single_word": false,
42
+ "special": true
43
+ },
44
+ "32002": {
45
+ "content": "<extra_id_97>",
46
+ "lstrip": false,
47
+ "normalized": false,
48
+ "rstrip": false,
49
+ "single_word": false,
50
+ "special": true
51
+ },
52
+ "32003": {
53
+ "content": "<extra_id_96>",
54
+ "lstrip": false,
55
+ "normalized": false,
56
+ "rstrip": false,
57
+ "single_word": false,
58
+ "special": true
59
+ },
60
+ "32004": {
61
+ "content": "<extra_id_95>",
62
+ "lstrip": false,
63
+ "normalized": false,
64
+ "rstrip": false,
65
+ "single_word": false,
66
+ "special": true
67
+ },
68
+ "32005": {
69
+ "content": "<extra_id_94>",
70
+ "lstrip": false,
71
+ "normalized": false,
72
+ "rstrip": false,
73
+ "single_word": false,
74
+ "special": true
75
+ },
76
+ "32006": {
77
+ "content": "<extra_id_93>",
78
+ "lstrip": false,
79
+ "normalized": false,
80
+ "rstrip": false,
81
+ "single_word": false,
82
+ "special": true
83
+ },
84
+ "32007": {
85
+ "content": "<extra_id_92>",
86
+ "lstrip": false,
87
+ "normalized": false,
88
+ "rstrip": false,
89
+ "single_word": false,
90
+ "special": true
91
+ },
92
+ "32008": {
93
+ "content": "<extra_id_91>",
94
+ "lstrip": false,
95
+ "normalized": false,
96
+ "rstrip": false,
97
+ "single_word": false,
98
+ "special": true
99
+ },
100
+ "32009": {
101
+ "content": "<extra_id_90>",
102
+ "lstrip": false,
103
+ "normalized": false,
104
+ "rstrip": false,
105
+ "single_word": false,
106
+ "special": true
107
+ },
108
+ "32010": {
109
+ "content": "<extra_id_89>",
110
+ "lstrip": false,
111
+ "normalized": false,
112
+ "rstrip": false,
113
+ "single_word": false,
114
+ "special": true
115
+ },
116
+ "32011": {
117
+ "content": "<extra_id_88>",
118
+ "lstrip": false,
119
+ "normalized": false,
120
+ "rstrip": false,
121
+ "single_word": false,
122
+ "special": true
123
+ },
124
+ "32012": {
125
+ "content": "<extra_id_87>",
126
+ "lstrip": false,
127
+ "normalized": false,
128
+ "rstrip": false,
129
+ "single_word": false,
130
+ "special": true
131
+ },
132
+ "32013": {
133
+ "content": "<extra_id_86>",
134
+ "lstrip": false,
135
+ "normalized": false,
136
+ "rstrip": false,
137
+ "single_word": false,
138
+ "special": true
139
+ },
140
+ "32014": {
141
+ "content": "<extra_id_85>",
142
+ "lstrip": false,
143
+ "normalized": false,
144
+ "rstrip": false,
145
+ "single_word": false,
146
+ "special": true
147
+ },
148
+ "32015": {
149
+ "content": "<extra_id_84>",
150
+ "lstrip": false,
151
+ "normalized": false,
152
+ "rstrip": false,
153
+ "single_word": false,
154
+ "special": true
155
+ },
156
+ "32016": {
157
+ "content": "<extra_id_83>",
158
+ "lstrip": false,
159
+ "normalized": false,
160
+ "rstrip": false,
161
+ "single_word": false,
162
+ "special": true
163
+ },
164
+ "32017": {
165
+ "content": "<extra_id_82>",
166
+ "lstrip": false,
167
+ "normalized": false,
168
+ "rstrip": false,
169
+ "single_word": false,
170
+ "special": true
171
+ },
172
+ "32018": {
173
+ "content": "<extra_id_81>",
174
+ "lstrip": false,
175
+ "normalized": false,
176
+ "rstrip": false,
177
+ "single_word": false,
178
+ "special": true
179
+ },
180
+ "32019": {
181
+ "content": "<extra_id_80>",
182
+ "lstrip": false,
183
+ "normalized": false,
184
+ "rstrip": false,
185
+ "single_word": false,
186
+ "special": true
187
+ },
188
+ "32020": {
189
+ "content": "<extra_id_79>",
190
+ "lstrip": false,
191
+ "normalized": false,
192
+ "rstrip": false,
193
+ "single_word": false,
194
+ "special": true
195
+ },
196
+ "32021": {
197
+ "content": "<extra_id_78>",
198
+ "lstrip": false,
199
+ "normalized": false,
200
+ "rstrip": false,
201
+ "single_word": false,
202
+ "special": true
203
+ },
204
+ "32022": {
205
+ "content": "<extra_id_77>",
206
+ "lstrip": false,
207
+ "normalized": false,
208
+ "rstrip": false,
209
+ "single_word": false,
210
+ "special": true
211
+ },
212
+ "32023": {
213
+ "content": "<extra_id_76>",
214
+ "lstrip": false,
215
+ "normalized": false,
216
+ "rstrip": false,
217
+ "single_word": false,
218
+ "special": true
219
+ },
220
+ "32024": {
221
+ "content": "<extra_id_75>",
222
+ "lstrip": false,
223
+ "normalized": false,
224
+ "rstrip": false,
225
+ "single_word": false,
226
+ "special": true
227
+ },
228
+ "32025": {
229
+ "content": "<extra_id_74>",
230
+ "lstrip": false,
231
+ "normalized": false,
232
+ "rstrip": false,
233
+ "single_word": false,
234
+ "special": true
235
+ },
236
+ "32026": {
237
+ "content": "<extra_id_73>",
238
+ "lstrip": false,
239
+ "normalized": false,
240
+ "rstrip": false,
241
+ "single_word": false,
242
+ "special": true
243
+ },
244
+ "32027": {
245
+ "content": "<extra_id_72>",
246
+ "lstrip": false,
247
+ "normalized": false,
248
+ "rstrip": false,
249
+ "single_word": false,
250
+ "special": true
251
+ },
252
+ "32028": {
253
+ "content": "<extra_id_71>",
254
+ "lstrip": false,
255
+ "normalized": false,
256
+ "rstrip": false,
257
+ "single_word": false,
258
+ "special": true
259
+ },
260
+ "32029": {
261
+ "content": "<extra_id_70>",
262
+ "lstrip": false,
263
+ "normalized": false,
264
+ "rstrip": false,
265
+ "single_word": false,
266
+ "special": true
267
+ },
268
+ "32030": {
269
+ "content": "<extra_id_69>",
270
+ "lstrip": false,
271
+ "normalized": false,
272
+ "rstrip": false,
273
+ "single_word": false,
274
+ "special": true
275
+ },
276
+ "32031": {
277
+ "content": "<extra_id_68>",
278
+ "lstrip": false,
279
+ "normalized": false,
280
+ "rstrip": false,
281
+ "single_word": false,
282
+ "special": true
283
+ },
284
+ "32032": {
285
+ "content": "<extra_id_67>",
286
+ "lstrip": false,
287
+ "normalized": false,
288
+ "rstrip": false,
289
+ "single_word": false,
290
+ "special": true
291
+ },
292
+ "32033": {
293
+ "content": "<extra_id_66>",
294
+ "lstrip": false,
295
+ "normalized": false,
296
+ "rstrip": false,
297
+ "single_word": false,
298
+ "special": true
299
+ },
300
+ "32034": {
301
+ "content": "<extra_id_65>",
302
+ "lstrip": false,
303
+ "normalized": false,
304
+ "rstrip": false,
305
+ "single_word": false,
306
+ "special": true
307
+ },
308
+ "32035": {
309
+ "content": "<extra_id_64>",
310
+ "lstrip": false,
311
+ "normalized": false,
312
+ "rstrip": false,
313
+ "single_word": false,
314
+ "special": true
315
+ },
316
+ "32036": {
317
+ "content": "<extra_id_63>",
318
+ "lstrip": false,
319
+ "normalized": false,
320
+ "rstrip": false,
321
+ "single_word": false,
322
+ "special": true
323
+ },
324
+ "32037": {
325
+ "content": "<extra_id_62>",
326
+ "lstrip": false,
327
+ "normalized": false,
328
+ "rstrip": false,
329
+ "single_word": false,
330
+ "special": true
331
+ },
332
+ "32038": {
333
+ "content": "<extra_id_61>",
334
+ "lstrip": false,
335
+ "normalized": false,
336
+ "rstrip": false,
337
+ "single_word": false,
338
+ "special": true
339
+ },
340
+ "32039": {
341
+ "content": "<extra_id_60>",
342
+ "lstrip": false,
343
+ "normalized": false,
344
+ "rstrip": false,
345
+ "single_word": false,
346
+ "special": true
347
+ },
348
+ "32040": {
349
+ "content": "<extra_id_59>",
350
+ "lstrip": false,
351
+ "normalized": false,
352
+ "rstrip": false,
353
+ "single_word": false,
354
+ "special": true
355
+ },
356
+ "32041": {
357
+ "content": "<extra_id_58>",
358
+ "lstrip": false,
359
+ "normalized": false,
360
+ "rstrip": false,
361
+ "single_word": false,
362
+ "special": true
363
+ },
364
+ "32042": {
365
+ "content": "<extra_id_57>",
366
+ "lstrip": false,
367
+ "normalized": false,
368
+ "rstrip": false,
369
+ "single_word": false,
370
+ "special": true
371
+ },
372
+ "32043": {
373
+ "content": "<extra_id_56>",
374
+ "lstrip": false,
375
+ "normalized": false,
376
+ "rstrip": false,
377
+ "single_word": false,
378
+ "special": true
379
+ },
380
+ "32044": {
381
+ "content": "<extra_id_55>",
382
+ "lstrip": false,
383
+ "normalized": false,
384
+ "rstrip": false,
385
+ "single_word": false,
386
+ "special": true
387
+ },
388
+ "32045": {
389
+ "content": "<extra_id_54>",
390
+ "lstrip": false,
391
+ "normalized": false,
392
+ "rstrip": false,
393
+ "single_word": false,
394
+ "special": true
395
+ },
396
+ "32046": {
397
+ "content": "<extra_id_53>",
398
+ "lstrip": false,
399
+ "normalized": false,
400
+ "rstrip": false,
401
+ "single_word": false,
402
+ "special": true
403
+ },
404
+ "32047": {
405
+ "content": "<extra_id_52>",
406
+ "lstrip": false,
407
+ "normalized": false,
408
+ "rstrip": false,
409
+ "single_word": false,
410
+ "special": true
411
+ },
412
+ "32048": {
413
+ "content": "<extra_id_51>",
414
+ "lstrip": false,
415
+ "normalized": false,
416
+ "rstrip": false,
417
+ "single_word": false,
418
+ "special": true
419
+ },
420
+ "32049": {
421
+ "content": "<extra_id_50>",
422
+ "lstrip": false,
423
+ "normalized": false,
424
+ "rstrip": false,
425
+ "single_word": false,
426
+ "special": true
427
+ },
428
+ "32050": {
429
+ "content": "<extra_id_49>",
430
+ "lstrip": false,
431
+ "normalized": false,
432
+ "rstrip": false,
433
+ "single_word": false,
434
+ "special": true
435
+ },
436
+ "32051": {
437
+ "content": "<extra_id_48>",
438
+ "lstrip": false,
439
+ "normalized": false,
440
+ "rstrip": false,
441
+ "single_word": false,
442
+ "special": true
443
+ },
444
+ "32052": {
445
+ "content": "<extra_id_47>",
446
+ "lstrip": false,
447
+ "normalized": false,
448
+ "rstrip": false,
449
+ "single_word": false,
450
+ "special": true
451
+ },
452
+ "32053": {
453
+ "content": "<extra_id_46>",
454
+ "lstrip": false,
455
+ "normalized": false,
456
+ "rstrip": false,
457
+ "single_word": false,
458
+ "special": true
459
+ },
460
+ "32054": {
461
+ "content": "<extra_id_45>",
462
+ "lstrip": false,
463
+ "normalized": false,
464
+ "rstrip": false,
465
+ "single_word": false,
466
+ "special": true
467
+ },
468
+ "32055": {
469
+ "content": "<extra_id_44>",
470
+ "lstrip": false,
471
+ "normalized": false,
472
+ "rstrip": false,
473
+ "single_word": false,
474
+ "special": true
475
+ },
476
+ "32056": {
477
+ "content": "<extra_id_43>",
478
+ "lstrip": false,
479
+ "normalized": false,
480
+ "rstrip": false,
481
+ "single_word": false,
482
+ "special": true
483
+ },
484
+ "32057": {
485
+ "content": "<extra_id_42>",
486
+ "lstrip": false,
487
+ "normalized": false,
488
+ "rstrip": false,
489
+ "single_word": false,
490
+ "special": true
491
+ },
492
+ "32058": {
493
+ "content": "<extra_id_41>",
494
+ "lstrip": false,
495
+ "normalized": false,
496
+ "rstrip": false,
497
+ "single_word": false,
498
+ "special": true
499
+ },
500
+ "32059": {
501
+ "content": "<extra_id_40>",
502
+ "lstrip": false,
503
+ "normalized": false,
504
+ "rstrip": false,
505
+ "single_word": false,
506
+ "special": true
507
+ },
508
+ "32060": {
509
+ "content": "<extra_id_39>",
510
+ "lstrip": false,
511
+ "normalized": false,
512
+ "rstrip": false,
513
+ "single_word": false,
514
+ "special": true
515
+ },
516
+ "32061": {
517
+ "content": "<extra_id_38>",
518
+ "lstrip": false,
519
+ "normalized": false,
520
+ "rstrip": false,
521
+ "single_word": false,
522
+ "special": true
523
+ },
524
+ "32062": {
525
+ "content": "<extra_id_37>",
526
+ "lstrip": false,
527
+ "normalized": false,
528
+ "rstrip": false,
529
+ "single_word": false,
530
+ "special": true
531
+ },
532
+ "32063": {
533
+ "content": "<extra_id_36>",
534
+ "lstrip": false,
535
+ "normalized": false,
536
+ "rstrip": false,
537
+ "single_word": false,
538
+ "special": true
539
+ },
540
+ "32064": {
541
+ "content": "<extra_id_35>",
542
+ "lstrip": false,
543
+ "normalized": false,
544
+ "rstrip": false,
545
+ "single_word": false,
546
+ "special": true
547
+ },
548
+ "32065": {
549
+ "content": "<extra_id_34>",
550
+ "lstrip": false,
551
+ "normalized": false,
552
+ "rstrip": false,
553
+ "single_word": false,
554
+ "special": true
555
+ },
556
+ "32066": {
557
+ "content": "<extra_id_33>",
558
+ "lstrip": false,
559
+ "normalized": false,
560
+ "rstrip": false,
561
+ "single_word": false,
562
+ "special": true
563
+ },
564
+ "32067": {
565
+ "content": "<extra_id_32>",
566
+ "lstrip": false,
567
+ "normalized": false,
568
+ "rstrip": false,
569
+ "single_word": false,
570
+ "special": true
571
+ },
572
+ "32068": {
573
+ "content": "<extra_id_31>",
574
+ "lstrip": false,
575
+ "normalized": false,
576
+ "rstrip": false,
577
+ "single_word": false,
578
+ "special": true
579
+ },
580
+ "32069": {
581
+ "content": "<extra_id_30>",
582
+ "lstrip": false,
583
+ "normalized": false,
584
+ "rstrip": false,
585
+ "single_word": false,
586
+ "special": true
587
+ },
588
+ "32070": {
589
+ "content": "<extra_id_29>",
590
+ "lstrip": false,
591
+ "normalized": false,
592
+ "rstrip": false,
593
+ "single_word": false,
594
+ "special": true
595
+ },
596
+ "32071": {
597
+ "content": "<extra_id_28>",
598
+ "lstrip": false,
599
+ "normalized": false,
600
+ "rstrip": false,
601
+ "single_word": false,
602
+ "special": true
603
+ },
604
+ "32072": {
605
+ "content": "<extra_id_27>",
606
+ "lstrip": false,
607
+ "normalized": false,
608
+ "rstrip": false,
609
+ "single_word": false,
610
+ "special": true
611
+ },
612
+ "32073": {
613
+ "content": "<extra_id_26>",
614
+ "lstrip": false,
615
+ "normalized": false,
616
+ "rstrip": false,
617
+ "single_word": false,
618
+ "special": true
619
+ },
620
+ "32074": {
621
+ "content": "<extra_id_25>",
622
+ "lstrip": false,
623
+ "normalized": false,
624
+ "rstrip": false,
625
+ "single_word": false,
626
+ "special": true
627
+ },
628
+ "32075": {
629
+ "content": "<extra_id_24>",
630
+ "lstrip": false,
631
+ "normalized": false,
632
+ "rstrip": false,
633
+ "single_word": false,
634
+ "special": true
635
+ },
636
+ "32076": {
637
+ "content": "<extra_id_23>",
638
+ "lstrip": false,
639
+ "normalized": false,
640
+ "rstrip": false,
641
+ "single_word": false,
642
+ "special": true
643
+ },
644
+ "32077": {
645
+ "content": "<extra_id_22>",
646
+ "lstrip": false,
647
+ "normalized": false,
648
+ "rstrip": false,
649
+ "single_word": false,
650
+ "special": true
651
+ },
652
+ "32078": {
653
+ "content": "<extra_id_21>",
654
+ "lstrip": false,
655
+ "normalized": false,
656
+ "rstrip": false,
657
+ "single_word": false,
658
+ "special": true
659
+ },
660
+ "32079": {
661
+ "content": "<extra_id_20>",
662
+ "lstrip": false,
663
+ "normalized": false,
664
+ "rstrip": false,
665
+ "single_word": false,
666
+ "special": true
667
+ },
668
+ "32080": {
669
+ "content": "<extra_id_19>",
670
+ "lstrip": false,
671
+ "normalized": false,
672
+ "rstrip": false,
673
+ "single_word": false,
674
+ "special": true
675
+ },
676
+ "32081": {
677
+ "content": "<extra_id_18>",
678
+ "lstrip": false,
679
+ "normalized": false,
680
+ "rstrip": false,
681
+ "single_word": false,
682
+ "special": true
683
+ },
684
+ "32082": {
685
+ "content": "<extra_id_17>",
686
+ "lstrip": false,
687
+ "normalized": false,
688
+ "rstrip": false,
689
+ "single_word": false,
690
+ "special": true
691
+ },
692
+ "32083": {
693
+ "content": "<extra_id_16>",
694
+ "lstrip": false,
695
+ "normalized": false,
696
+ "rstrip": false,
697
+ "single_word": false,
698
+ "special": true
699
+ },
700
+ "32084": {
701
+ "content": "<extra_id_15>",
702
+ "lstrip": false,
703
+ "normalized": false,
704
+ "rstrip": false,
705
+ "single_word": false,
706
+ "special": true
707
+ },
708
+ "32085": {
709
+ "content": "<extra_id_14>",
710
+ "lstrip": false,
711
+ "normalized": false,
712
+ "rstrip": false,
713
+ "single_word": false,
714
+ "special": true
715
+ },
716
+ "32086": {
717
+ "content": "<extra_id_13>",
718
+ "lstrip": false,
719
+ "normalized": false,
720
+ "rstrip": false,
721
+ "single_word": false,
722
+ "special": true
723
+ },
724
+ "32087": {
725
+ "content": "<extra_id_12>",
726
+ "lstrip": false,
727
+ "normalized": false,
728
+ "rstrip": false,
729
+ "single_word": false,
730
+ "special": true
731
+ },
732
+ "32088": {
733
+ "content": "<extra_id_11>",
734
+ "lstrip": false,
735
+ "normalized": false,
736
+ "rstrip": false,
737
+ "single_word": false,
738
+ "special": true
739
+ },
740
+ "32089": {
741
+ "content": "<extra_id_10>",
742
+ "lstrip": false,
743
+ "normalized": false,
744
+ "rstrip": false,
745
+ "single_word": false,
746
+ "special": true
747
+ },
748
+ "32090": {
749
+ "content": "<extra_id_9>",
750
+ "lstrip": false,
751
+ "normalized": false,
752
+ "rstrip": false,
753
+ "single_word": false,
754
+ "special": true
755
+ },
756
+ "32091": {
757
+ "content": "<extra_id_8>",
758
+ "lstrip": false,
759
+ "normalized": false,
760
+ "rstrip": false,
761
+ "single_word": false,
762
+ "special": true
763
+ },
764
+ "32092": {
765
+ "content": "<extra_id_7>",
766
+ "lstrip": false,
767
+ "normalized": false,
768
+ "rstrip": false,
769
+ "single_word": false,
770
+ "special": true
771
+ },
772
+ "32093": {
773
+ "content": "<extra_id_6>",
774
+ "lstrip": false,
775
+ "normalized": false,
776
+ "rstrip": false,
777
+ "single_word": false,
778
+ "special": true
779
+ },
780
+ "32094": {
781
+ "content": "<extra_id_5>",
782
+ "lstrip": false,
783
+ "normalized": false,
784
+ "rstrip": false,
785
+ "single_word": false,
786
+ "special": true
787
+ },
788
+ "32095": {
789
+ "content": "<extra_id_4>",
790
+ "lstrip": false,
791
+ "normalized": false,
792
+ "rstrip": false,
793
+ "single_word": false,
794
+ "special": true
795
+ },
796
+ "32096": {
797
+ "content": "<extra_id_3>",
798
+ "lstrip": false,
799
+ "normalized": false,
800
+ "rstrip": false,
801
+ "single_word": false,
802
+ "special": true
803
+ },
804
+ "32097": {
805
+ "content": "<extra_id_2>",
806
+ "lstrip": false,
807
+ "normalized": false,
808
+ "rstrip": false,
809
+ "single_word": false,
810
+ "special": true
811
+ },
812
+ "32098": {
813
+ "content": "<extra_id_1>",
814
+ "lstrip": false,
815
+ "normalized": false,
816
+ "rstrip": false,
817
+ "single_word": false,
818
+ "special": true
819
+ },
820
+ "32099": {
821
+ "content": "<extra_id_0>",
822
+ "lstrip": false,
823
+ "normalized": false,
824
+ "rstrip": false,
825
+ "single_word": false,
826
+ "special": true
827
+ }
828
+ },
829
+ "additional_special_tokens": [
830
+ "<extra_id_0>",
831
+ "<extra_id_1>",
832
+ "<extra_id_2>",
833
+ "<extra_id_3>",
834
+ "<extra_id_4>",
835
+ "<extra_id_5>",
836
+ "<extra_id_6>",
837
+ "<extra_id_7>",
838
+ "<extra_id_8>",
839
+ "<extra_id_9>",
840
+ "<extra_id_10>",
841
+ "<extra_id_11>",
842
+ "<extra_id_12>",
843
+ "<extra_id_13>",
844
+ "<extra_id_14>",
845
+ "<extra_id_15>",
846
+ "<extra_id_16>",
847
+ "<extra_id_17>",
848
+ "<extra_id_18>",
849
+ "<extra_id_19>",
850
+ "<extra_id_20>",
851
+ "<extra_id_21>",
852
+ "<extra_id_22>",
853
+ "<extra_id_23>",
854
+ "<extra_id_24>",
855
+ "<extra_id_25>",
856
+ "<extra_id_26>",
857
+ "<extra_id_27>",
858
+ "<extra_id_28>",
859
+ "<extra_id_29>",
860
+ "<extra_id_30>",
861
+ "<extra_id_31>",
862
+ "<extra_id_32>",
863
+ "<extra_id_33>",
864
+ "<extra_id_34>",
865
+ "<extra_id_35>",
866
+ "<extra_id_36>",
867
+ "<extra_id_37>",
868
+ "<extra_id_38>",
869
+ "<extra_id_39>",
870
+ "<extra_id_40>",
871
+ "<extra_id_41>",
872
+ "<extra_id_42>",
873
+ "<extra_id_43>",
874
+ "<extra_id_44>",
875
+ "<extra_id_45>",
876
+ "<extra_id_46>",
877
+ "<extra_id_47>",
878
+ "<extra_id_48>",
879
+ "<extra_id_49>",
880
+ "<extra_id_50>",
881
+ "<extra_id_51>",
882
+ "<extra_id_52>",
883
+ "<extra_id_53>",
884
+ "<extra_id_54>",
885
+ "<extra_id_55>",
886
+ "<extra_id_56>",
887
+ "<extra_id_57>",
888
+ "<extra_id_58>",
889
+ "<extra_id_59>",
890
+ "<extra_id_60>",
891
+ "<extra_id_61>",
892
+ "<extra_id_62>",
893
+ "<extra_id_63>",
894
+ "<extra_id_64>",
895
+ "<extra_id_65>",
896
+ "<extra_id_66>",
897
+ "<extra_id_67>",
898
+ "<extra_id_68>",
899
+ "<extra_id_69>",
900
+ "<extra_id_70>",
901
+ "<extra_id_71>",
902
+ "<extra_id_72>",
903
+ "<extra_id_73>",
904
+ "<extra_id_74>",
905
+ "<extra_id_75>",
906
+ "<extra_id_76>",
907
+ "<extra_id_77>",
908
+ "<extra_id_78>",
909
+ "<extra_id_79>",
910
+ "<extra_id_80>",
911
+ "<extra_id_81>",
912
+ "<extra_id_82>",
913
+ "<extra_id_83>",
914
+ "<extra_id_84>",
915
+ "<extra_id_85>",
916
+ "<extra_id_86>",
917
+ "<extra_id_87>",
918
+ "<extra_id_88>",
919
+ "<extra_id_89>",
920
+ "<extra_id_90>",
921
+ "<extra_id_91>",
922
+ "<extra_id_92>",
923
+ "<extra_id_93>",
924
+ "<extra_id_94>",
925
+ "<extra_id_95>",
926
+ "<extra_id_96>",
927
+ "<extra_id_97>",
928
+ "<extra_id_98>",
929
+ "<extra_id_99>"
930
+ ],
931
+ "clean_up_tokenization_spaces": true,
932
+ "eos_token": "</s>",
933
+ "extra_ids": 100,
934
+ "extra_special_tokens": {},
935
+ "model_max_length": 512,
936
+ "pad_token": "<pad>",
937
+ "tokenizer_class": "T5Tokenizer",
938
+ "unk_token": "<unk>"
939
+ }
xgb_band gap bulk.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2dce1313ec3ce92b6019b8b9071f7bec96deb27eb15177c43267baac4a2a87e0
3
+ size 179430
xgb_band gap chain.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:791b1c9d7de1564baf5f04b397a4c487a334d19ca5e7828463b6b7e6facff5e5
3
+ size 269055
xgb_bandgap-crystal.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:24b0cc7edda31ac607ff8e13f259bbbaf62e995977b9c7655835806be3027f7e
3
+ size 150871
xgb_cte.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3fbb04ce5771d9dad717d7f4d7fe7234f66d8d973da74b3261805f5f2ee1a191
3
+ size 520320
xgb_gaspermability.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cc20231f90a77da7fb9f7fac05dd0aabcbfdc8b70ddc440697419fc6cd3b2a0f
3
+ size 443720
xgb_loi.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1c972fcea91d3066659327a8b3bbcab3cfe5c2aebddbf476cae71885ee71a8dd
3
+ size 544399
xgb_solubility.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5cee16a2a1010d7754801452a816c0187a4b70ade97defa1d03a7b3277d590cd
3
+ size 516200
xgb_td.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c29ca68268e50b016f0b9acab03fd47bee3deee1f690816aca805704e99fd499
3
+ size 7218153
xgb_tg.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1cbed399cb5dfe36ba48b81637f5ad5c5a6b0c2a25942abcdf232b8d09a7678d
3
+ size 2006300
xgb_thermal_cond.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:38bdd642b03d04e95ec3411eb6145e863b9e8101d79c87d0ae45ea0863b81f6a
3
+ size 502815
xgb_tm.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:54e183e50d94c6673c6ccdbb2f2bd73cc0ea7752427822b099980b81ed3eb62a
3
+ size 253017