openfree commited on
Commit
096059a
·
verified ·
1 Parent(s): dcdaa08

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +1 -1588
app.py CHANGED
@@ -1,1589 +1,2 @@
1
- import os,sys
2
- import traceback # 상단에 추가
3
- # install required packages
4
- os.system('pip install plotly') # plotly 설치
5
- os.system('pip install matplotlib') # matplotlib 설치
6
- os.system('pip install dgl==1.0.2+cu116 -f https://data.dgl.ai/wheels/cu116/repo.html')
7
- os.environ["DGLBACKEND"] = "pytorch"
8
- print('Modules installed')
9
-
10
- # 기본 args 설정
11
- if not os.path.exists('./tmp'):
12
- os.makedirs('./tmp')
13
-
14
- if not os.path.exists('./tmp/args.json'):
15
- default_args = {
16
- 'checkpoint': None,
17
- 'dump_trb': False,
18
- 'dump_args': True,
19
- 'save_best_plddt': True,
20
- 'T': 25,
21
- 'strand_bias': 0.0,
22
- 'loop_bias': 0.0,
23
- 'helix_bias': 0.0,
24
- 'd_t1d': 24,
25
- 'potentials': None,
26
- 'potential_scale': None,
27
- 'aa_composition': None
28
- }
29
- with open('./tmp/args.json', 'w') as f:
30
- json.dump(default_args, f)
31
-
32
- # 체크포인트 파일 다운로드
33
- if not os.path.exists('./SEQDIFF_230205_dssp_hotspots_25mask_EQtasks_mod30.pt'):
34
- print('Downloading model weights 1')
35
- os.system('wget http://files.ipd.uw.edu/pub/sequence_diffusion/checkpoints/SEQDIFF_230205_dssp_hotspots_25mask_EQtasks_mod30.pt')
36
- print('Successfully Downloaded')
37
-
38
- if not os.path.exists('./SEQDIFF_221219_equalTASKS_nostrSELFCOND_mod30.pt'):
39
- print('Downloading model weights 2')
40
- os.system('wget http://files.ipd.uw.edu/pub/sequence_diffusion/checkpoints/SEQDIFF_221219_equalTASKS_nostrSELFCOND_mod30.pt')
41
- print('Successfully Downloaded')
42
-
43
- from openai import OpenAI
44
- import gradio as gr
45
- import json # json 모듈 추가
46
- from datasets import load_dataset
47
- import plotly.graph_objects as go
48
- import numpy as np
49
- import py3Dmol
50
- from io import StringIO
51
- import json
52
- import secrets
53
- import copy
54
- import matplotlib.pyplot as plt
55
- from utils.sampler import HuggingFace_sampler
56
- from utils.parsers_inference import parse_pdb
57
- from model.util import writepdb
58
- from utils.inpainting_util import *
59
  import os
60
-
61
- # args 로드
62
- with open('./tmp/args.json', 'r') as f:
63
- args = json.load(f)
64
-
65
- plt.rcParams.update({'font.size': 13})
66
-
67
- # manually set checkpoint to load
68
- args['checkpoint'] = None
69
- args['dump_trb'] = False
70
- args['dump_args'] = True
71
- args['save_best_plddt'] = True
72
- args['T'] = 25
73
- args['strand_bias'] = 0.0
74
- args['loop_bias'] = 0.0
75
- args['helix_bias'] = 0.0
76
-
77
- # Hugging Face 토큰 설정
78
- ACCESS_TOKEN = os.getenv("HF_TOKEN")
79
- if not ACCESS_TOKEN:
80
- raise ValueError("HF_TOKEN not found in environment variables")
81
-
82
- # OpenAI 클라이언트 설정 (Hugging Face 엔드포인트 사용)
83
- client = OpenAI(
84
- base_url="https://api-inference.huggingface.co/v1/",
85
- api_key=ACCESS_TOKEN,
86
- )
87
-
88
-
89
- # 데이터셋 로드 및 구조 확인
90
- try:
91
- ds = load_dataset("lamm-mit/protein_secondary_structure_from_PDB",
92
- token=ACCESS_TOKEN)
93
- print("Dataset structure:", ds)
94
- print("First entry example:", next(iter(ds['train'])))
95
- except Exception as e:
96
- print(f"Dataset loading error: {str(e)}")
97
- raise
98
-
99
- def respond(
100
- message,
101
- history,
102
- system_message,
103
- max_tokens,
104
- temperature,
105
- top_p,
106
- ):
107
- messages = [{"role": "system", "content": system_message}]
108
-
109
- for msg in history:
110
- messages.append({"role": "user", "content": msg[0]})
111
- if msg[1]:
112
- messages.append({"role": "assistant", "content": msg[1]})
113
-
114
- messages.append({"role": "user", "content": message})
115
-
116
- try:
117
- response = ""
118
- for chunk in client.chat.completions.create(
119
- model="CohereForAI/c4ai-command-r-plus-08-2024",
120
- max_tokens=max_tokens,
121
- stream=True,
122
- temperature=temperature,
123
- top_p=top_p,
124
- messages=messages,
125
- ):
126
- if hasattr(chunk.choices[0].delta, 'content'):
127
- token = chunk.choices[0].delta.content
128
- if token is not None:
129
- response += token
130
- yield [{"role": "user", "content": message},
131
- {"role": "assistant", "content": response}]
132
-
133
- return [{"role": "user", "content": message},
134
- {"role": "assistant", "content": response}]
135
- except Exception as e:
136
- print(f"Error in respond: {str(e)}")
137
- return [{"role": "user", "content": message},
138
- {"role": "assistant", "content": f"오류가 발생했습니다: {str(e)}"}]
139
-
140
- def analyze_prompt(message):
141
- """LLM을 사용하여 프롬프트 분석"""
142
- try:
143
- analysis_prompt = f"""
144
- 다음 요청을 분석하여 단백질 설계에 필요한 주요 특성을 추출하세요:
145
- 요청: {message}
146
-
147
- 다음 항목들을 분석해주세요:
148
- 1. 주요 기능 (예: 치료, 결합, 촉매 등)
149
- 2. 목표 환경 (예: 세포막, 수용성, 등)
150
- 3. 필요한 구조적 특징
151
- 4. 크기 및 복잡도 요구사항
152
- """
153
-
154
- response = client.chat.completions.create(
155
- model="CohereForAI/c4ai-command-r-plus-08-2024",
156
- messages=[{"role": "user", "content": analysis_prompt}],
157
- temperature=0.7
158
- )
159
-
160
- return response.choices[0].message.content
161
- except Exception as e:
162
- print(f"프롬프트 분석 중 오류: {str(e)}")
163
- return None
164
-
165
- def search_protein_data(analysis, dataset):
166
- """분석 결과를 바탕으로 데이터셋에서 유사한 구조 검색"""
167
- try:
168
- # 키워드 추출
169
- keywords = extract_keywords(analysis)
170
- print("Extracted keywords:", keywords)
171
-
172
- # 데이터셋 구조 확인
173
- if not dataset or 'train' not in dataset:
174
- print("Invalid dataset structure")
175
- return []
176
-
177
- # 유사도 점수 계산
178
- scored_entries = []
179
- for entry in dataset['train']:
180
- try:
181
- score = calculate_similarity(keywords, entry)
182
- scored_entries.append((score, entry))
183
- except Exception as e:
184
- print(f"Error processing entry: {str(e)}")
185
- continue
186
-
187
- # 결과 정렬 및 반환
188
- scored_entries.sort(reverse=True)
189
- return scored_entries[:3]
190
-
191
- except Exception as e:
192
- print(f"데이터 검색 중 오류: {str(e)}")
193
- return []
194
-
195
- def extract_parameters(analysis, similar_structures):
196
- """분석 결과와 유사 구조를 바탕으로 생성 파라미터 결정"""
197
- try:
198
- # 기본 파라미터 템플릿
199
- params = {
200
- 'sequence_length': 100,
201
- 'helix_bias': 0.02,
202
- 'strand_bias': 0.02,
203
- 'loop_bias': 0.1,
204
- 'hydrophobic_target_score': 0
205
- }
206
-
207
- # 분석 결과에서 구조적 요구사항 파악
208
- if "막 투과" in analysis or "소수성" in analysis:
209
- params['hydrophobic_target_score'] = -2
210
- params['helix_bias'] = 0.03
211
- elif "수용성" in analysis or "가용성" in analysis:
212
- params['hydrophobic_target_score'] = 2
213
- params['loop_bias'] = 0.15
214
-
215
- # 유사 구조들의 특성 반영
216
- if similar_structures:
217
- avg_length = sum(len(s[1]['sequence']) for s in similar_structures) / len(similar_structures)
218
- params['sequence_length'] = int(avg_length)
219
-
220
- # 구조적 특성 분석 및 반영
221
- for _, structure in similar_structures:
222
- if 'secondary_structure' in structure:
223
- helix_ratio = structure['secondary_structure'].count('H') / len(structure['secondary_structure'])
224
- sheet_ratio = structure['secondary_structure'].count('E') / len(structure['secondary_structure'])
225
- params['helix_bias'] = max(0.01, min(0.05, helix_ratio))
226
- params['strand_bias'] = max(0.01, min(0.05, sheet_ratio))
227
-
228
- return params
229
- except Exception as e:
230
- print(f"파라미터 추출 중 오류: {str(e)}")
231
- return None
232
-
233
- def process_chat(message, history):
234
- try:
235
- if any(keyword in message.lower() for keyword in ['protein', 'generate', '단백질', '생성', '치료']):
236
- # 1. LLM을 사용한 프롬프트 분석
237
- analysis = analyze_prompt(message)
238
- if not analysis:
239
- return history + [
240
- {"role": "user", "content": message},
241
- {"role": "assistant", "content": "요청 분석에 실패했습니다."}
242
- ]
243
-
244
- # 2. 유사 구조 검색
245
- similar_structures = search_protein_data(analysis, ds)
246
- if not similar_structures:
247
- return history + [
248
- {"role": "user", "content": message},
249
- {"role": "assistant", "content": "적합한 참조 구조를 찾지 못했습니다."}
250
- ]
251
-
252
- # 3. 생성 파라미터 결정
253
- params = extract_parameters(analysis, similar_structures)
254
- if not params:
255
- return history + [
256
- {"role": "user", "content": message},
257
- {"role": "assistant", "content": "파라미터 설정에 실패했습니다."}
258
- ]
259
-
260
- # 4. 단백질 생성
261
- try:
262
- protein_result = protein_diffusion_model(
263
- sequence=None,
264
- seq_len=params['sequence_length'],
265
- helix_bias=params['helix_bias'],
266
- strand_bias=params['strand_bias'],
267
- loop_bias=params['loop_bias'],
268
- secondary_structure=None,
269
- aa_bias=None,
270
- aa_bias_potential=None,
271
- num_steps="25",
272
- noise="normal",
273
- hydrophobic_target_score=str(params['hydrophobic_target_score']),
274
- hydrophobic_potential="2",
275
- contigs=None,
276
- pssm=None,
277
- seq_mask=None,
278
- str_mask=None,
279
- rewrite_pdb=None
280
- )
281
-
282
- output_seq, output_pdb, structure_view, plddt_plot = next(protein_result)
283
-
284
- # 5. 결과 설명 생성
285
- explanation = f"""
286
- 요청하신 기능에 맞는 단백질을 생성했습니다:
287
-
288
- 분석된 요구사항:
289
- {analysis}
290
-
291
- 설계된 구조적 특징:
292
- - 길이: {params['sequence_length']} 아미노산
293
- - 알파 헬릭스 비율: {params['helix_bias']*100:.1f}%
294
- - 베타 시트 비율: {params['strand_bias']*100:.1f}%
295
- - 루프 구조 비율: {params['loop_bias']*100:.1f}%
296
- - 소수성 점수: {params['hydrophobic_target_score']}
297
-
298
- 참조된 유사 구조: {len(similar_structures)}개
299
-
300
- 생성된 단백질의 3D 구조와 시퀀스를 확인하실 수 있습니다.
301
- """
302
-
303
- # 6. 결과 저장
304
- global current_protein_result
305
- current_protein_result = {
306
- 'sequence': output_seq,
307
- 'pdb': output_pdb,
308
- 'structure_view': structure_view,
309
- 'plddt_plot': plddt_plot,
310
- 'params': params
311
- }
312
-
313
- return history + [
314
- {"role": "user", "content": message},
315
- {"role": "assistant", "content": explanation}
316
- ]
317
-
318
- except Exception as e:
319
- return history + [
320
- {"role": "user", "content": message},
321
- {"role": "assistant", "content": f"단백질 생성 중 오류가 발생했습니다: {str(e)}"}
322
- ]
323
- else:
324
- return history + [
325
- {"role": "user", "content": message},
326
- {"role": "assistant", "content": "단백질 생성 관련 키워드를 포함해주세요."}
327
- ]
328
- except Exception as e:
329
- return history + [
330
- {"role": "user", "content": message},
331
- {"role": "assistant", "content": f"처리 중 오류가 발생했습니다: {str(e)}"}
332
- ]
333
-
334
-
335
- def generate_protein(params):
336
- # 기존 protein_diffusion_model 함수 호출
337
- result = protein_diffusion_model(
338
- sequence=None,
339
- seq_len=params['sequence_length'],
340
- helix_bias=params['helix_bias'],
341
- strand_bias=params['strand_bias'],
342
- loop_bias=params['loop_bias'],
343
- secondary_structure=None,
344
- aa_bias=None,
345
- aa_bias_potential=None,
346
- num_steps="25",
347
- noise="normal",
348
- hydrophobic_target_score=str(params['hydrophobic_target_score']),
349
- hydrophobic_potential="2",
350
- contigs=None,
351
- pssm=None,
352
- seq_mask=None,
353
- str_mask=None,
354
- rewrite_pdb=None
355
- )
356
- return result
357
-
358
- def generate_explanation(result, params):
359
- explanation = f"""
360
- 생성된 단백질 분석:
361
- - 길이: {params['sequence_length']} 아미노산
362
- - 구조적 특징:
363
- * 알파 나선 비율: {params['helix_bias']*100}%
364
- * 베타 시트 비율: {params['strand_bias']*100}%
365
- * 루프 구조 비율: {params['loop_bias']*100}%
366
- - 특수 기능: {result.get('special_features', '없음')}
367
- """
368
- return explanation
369
-
370
- # 체크포인트 파일 경로를 절대 경로로 수정
371
- def protein_diffusion_model(sequence, seq_len, helix_bias, strand_bias, loop_bias,
372
- secondary_structure, aa_bias, aa_bias_potential,
373
- num_steps, noise, hydrophobic_target_score, hydrophobic_potential,
374
- contigs, pssm, seq_mask, str_mask, rewrite_pdb):
375
-
376
-
377
- dssp_checkpoint = './SEQDIFF_230205_dssp_hotspots_25mask_EQtasks_mod30.pt'
378
- og_checkpoint = './SEQDIFF_221219_equalTASKS_nostrSELFCOND_mod30.pt'
379
-
380
-
381
- # 체크포인트 파일 존재 확인
382
- if not os.path.exists(dssp_checkpoint):
383
- raise FileNotFoundError(f"DSSP checkpoint file not found at: {dssp_checkpoint}")
384
- if not os.path.exists(og_checkpoint):
385
- raise FileNotFoundError(f"OG checkpoint file not found at: {og_checkpoint}")
386
-
387
- model_args = copy.deepcopy(args)
388
-
389
-
390
- # make sampler
391
- S = HuggingFace_sampler(args=model_args)
392
-
393
- # get random prefix
394
- S.out_prefix = './tmp/'+secrets.token_hex(nbytes=10).upper()
395
-
396
- # set args
397
- S.args['checkpoint'] = None
398
- S.args['dump_trb'] = False
399
- S.args['dump_args'] = True
400
- S.args['save_best_plddt'] = True
401
- S.args['T'] = 25
402
- S.args['strand_bias'] = 0.0
403
- S.args['loop_bias'] = 0.0
404
- S.args['helix_bias'] = 0.0
405
- S.args['potentials'] = None
406
- S.args['potential_scale'] = None
407
- S.args['aa_composition'] = None
408
-
409
-
410
- # get sequence if entered and make sure all chars are valid
411
- alt_aa_dict = {'B':['D','N'],'J':['I','L'],'U':['C'],'Z':['E','Q'],'O':['K']}
412
- if sequence not in ['',None]:
413
- L = len(sequence)
414
- aa_seq = []
415
- for aa in sequence.upper():
416
- if aa in alt_aa_dict.keys():
417
- aa_seq.append(np.random.choice(alt_aa_dict[aa]))
418
- else:
419
- aa_seq.append(aa)
420
-
421
- S.args['sequence'] = aa_seq
422
- elif contigs not in ['',None]:
423
- S.args['contigs'] = [contigs]
424
- else:
425
- S.args['contigs'] = [f'{seq_len}']
426
- L = int(seq_len)
427
-
428
- print('DEBUG: ',rewrite_pdb)
429
- if rewrite_pdb not in ['',None]:
430
- S.args['pdb'] = rewrite_pdb.name
431
-
432
- if seq_mask not in ['',None]:
433
- S.args['inpaint_seq'] = [seq_mask]
434
- if str_mask not in ['',None]:
435
- S.args['inpaint_str'] = [str_mask]
436
-
437
- if secondary_structure in ['',None]:
438
- secondary_structure = None
439
- else:
440
- secondary_structure = ''.join(['E' if x == 'S' else x for x in secondary_structure])
441
- if L < len(secondary_structure):
442
- secondary_structure = secondary_structure[:len(sequence)]
443
- elif L == len(secondary_structure):
444
- pass
445
- else:
446
- dseq = L - len(secondary_structure)
447
- secondary_structure += secondary_structure[-1]*dseq
448
-
449
-
450
- # potentials
451
- potential_list = []
452
- potential_bias_list = []
453
-
454
- if aa_bias not in ['',None]:
455
- potential_list.append('aa_bias')
456
- S.args['aa_composition'] = aa_bias
457
- if aa_bias_potential in ['',None]:
458
- aa_bias_potential = 3
459
- potential_bias_list.append(str(aa_bias_potential))
460
- '''
461
- if target_charge not in ['',None]:
462
- potential_list.append('charge')
463
- if charge_potential in ['',None]:
464
- charge_potential = 1
465
- potential_bias_list.append(str(charge_potential))
466
- S.args['target_charge'] = float(target_charge)
467
- if target_ph in ['',None]:
468
- target_ph = 7.4
469
- S.args['target_pH'] = float(target_ph)
470
- '''
471
-
472
- if hydrophobic_target_score not in ['',None]:
473
- potential_list.append('hydrophobic')
474
- S.args['hydrophobic_score'] = float(hydrophobic_target_score)
475
- if hydrophobic_potential in ['',None]:
476
- hydrophobic_potential = 3
477
- potential_bias_list.append(str(hydrophobic_potential))
478
-
479
- if pssm not in ['',None]:
480
- potential_list.append('PSSM')
481
- potential_bias_list.append('5')
482
- S.args['PSSM'] = pssm.name
483
-
484
-
485
- if len(potential_list) > 0:
486
- S.args['potentials'] = ','.join(potential_list)
487
- S.args['potential_scale'] = ','.join(potential_bias_list)
488
-
489
-
490
- # normalise secondary_structure bias from range 0-0.3
491
- S.args['secondary_structure'] = secondary_structure
492
- S.args['helix_bias'] = helix_bias
493
- S.args['strand_bias'] = strand_bias
494
- S.args['loop_bias'] = loop_bias
495
-
496
- # set T
497
- if num_steps in ['',None]:
498
- S.args['T'] = 20
499
- else:
500
- S.args['T'] = int(num_steps)
501
-
502
- # noise
503
- if 'normal' in noise:
504
- S.args['sample_distribution'] = noise
505
- S.args['sample_distribution_gmm_means'] = [0]
506
- S.args['sample_distribution_gmm_variances'] = [1]
507
- elif 'gmm2' in noise:
508
- S.args['sample_distribution'] = noise
509
- S.args['sample_distribution_gmm_means'] = [-1,1]
510
- S.args['sample_distribution_gmm_variances'] = [1,1]
511
- elif 'gmm3' in noise:
512
- S.args['sample_distribution'] = noise
513
- S.args['sample_distribution_gmm_means'] = [-1,0,1]
514
- S.args['sample_distribution_gmm_variances'] = [1,1,1]
515
-
516
-
517
-
518
- if secondary_structure not in ['',None] or helix_bias+strand_bias+loop_bias > 0:
519
- S.args['checkpoint'] = dssp_checkpoint
520
- S.args['d_t1d'] = 29
521
- print('using dssp checkpoint')
522
- else:
523
- S.args['checkpoint'] = og_checkpoint
524
- S.args['d_t1d'] = 24
525
- print('using og checkpoint')
526
-
527
-
528
- for k,v in S.args.items():
529
- print(f"{k} --> {v}")
530
-
531
- # init S
532
- S.model_init()
533
- S.diffuser_init()
534
- S.setup()
535
-
536
- # sampling loop
537
- plddt_data = []
538
- for j in range(S.max_t):
539
- print(f'on step {j}')
540
- output_seq, output_pdb, plddt = S.take_step_get_outputs(j)
541
- plddt_data.append(plddt)
542
- yield output_seq, output_pdb, display_pdb(output_pdb), get_plddt_plot(plddt_data, S.max_t)
543
-
544
- output_seq, output_pdb, plddt = S.get_outputs()
545
-
546
- return output_seq, output_pdb, display_pdb(output_pdb), get_plddt_plot(plddt_data, S.max_t)
547
-
548
- def get_plddt_plot(plddt_data, max_t):
549
- fig, ax = plt.subplots(figsize=(15,6))
550
- x = list(range(1, len(plddt_data) + 1))
551
- ax.plot(x, plddt_data, color='#661dbf', linewidth=3, marker='o')
552
- ax.set_xticks(range(1, max_t + 1))
553
- ax.set_yticks([i/10 for i in range(11)]) # 0부터 1까지
554
- ax.set_ylim([0, 1])
555
- ax.set_ylabel('model confidence (plddt)')
556
- ax.set_xlabel('diffusion steps (t)')
557
- plt.close() # 메모리 관리를 위해 닫기
558
- return fig
559
-
560
-
561
- def display_pdb(path_to_pdb):
562
- '''
563
- #function to display pdb in py3dmol
564
- '''
565
- pdb = open(path_to_pdb, "r").read()
566
-
567
- view = py3Dmol.view(width=500, height=500)
568
- view.addModel(pdb, "pdb")
569
- view.setStyle({'model': -1}, {"cartoon": {'colorscheme':{'prop':'b','gradient':'roygb','min':0,'max':1}}})#'linear', 'min': 0, 'max': 1, 'colors': ["#ff9ef0","#a903fc",]}}})
570
- view.zoomTo()
571
- output = view._make_html().replace("'", '"')
572
- print(view._make_html())
573
- x = f"""<!DOCTYPE html><html></center> {output} </center></html>""" # do not use ' in this input
574
-
575
- return f"""<iframe height="500px" width="100%" name="result" allow="midi; geolocation; microphone; camera;
576
- display-capture; encrypted-media;" sandbox="allow-modals allow-forms
577
- allow-scripts allow-same-origin allow-popups
578
- allow-top-navigation-by-user-activation allow-downloads" allowfullscreen=""
579
- allowpaymentrequest="" frameborder="0" srcdoc='{x}'></iframe>"""
580
-
581
- '''
582
- return f"""<iframe style="width: 100%; height:700px" name="result" allow="midi; geolocation; microphone; camera;
583
- display-capture; encrypted-media;" sandbox="allow-modals allow-forms
584
- allow-scripts allow-same-origin allow-popups
585
- allow-top-navigation-by-user-activation allow-downloads" allowfullscreen=""
586
- allowpaymentrequest="" frameborder="0" srcdoc='{x}'></iframe>"""
587
- '''
588
-
589
- def get_motif_preview(pdb_id, contigs):
590
- try:
591
- input_pdb = fetch_pdb(pdb_id=pdb_id.lower() if pdb_id else None)
592
- if input_pdb is None:
593
- return gr.HTML("PDB ID를 입력해주세요"), None
594
-
595
- parse = parse_pdb(input_pdb)
596
- output_name = input_pdb
597
-
598
- pdb = open(output_name, "r").read()
599
- view = py3Dmol.view(width=500, height=500)
600
- view.addModel(pdb, "pdb")
601
-
602
- if contigs in ['',0]:
603
- contigs = ['0']
604
- else:
605
- contigs = [contigs]
606
-
607
- print('DEBUG: ',contigs)
608
-
609
- pdb_map = get_mappings(ContigMap(parse,contigs))
610
- print('DEBUG: ',pdb_map)
611
- print('DEBUG: ',pdb_map['con_ref_idx0'])
612
- roi = [x[1]-1 for x in pdb_map['con_ref_pdb_idx']]
613
-
614
- colormap = {0:'#D3D3D3', 1:'#F74CFF'}
615
- colors = {i+1: colormap[1] if i in roi else colormap[0] for i in range(parse['xyz'].shape[0])}
616
- view.setStyle({"cartoon": {"colorscheme": {"prop": "resi", "map": colors}}})
617
- view.zoomTo()
618
- output = view._make_html().replace("'", '"')
619
- print(view._make_html())
620
- x = f"""<!DOCTYPE html><html></center> {output} </center></html>""" # do not use ' in this input
621
-
622
- return f"""<iframe height="500px" width="100%" name="result" allow="midi; geolocation; microphone; camera;
623
- display-capture; encrypted-media;" sandbox="allow-modals allow-forms
624
- allow-scripts allow-same-origin allow-popups
625
- allow-top-navigation-by-user-activation allow-downloads" allowfullscreen=""
626
- allowpaymentrequest="" frameborder="0" srcdoc='{x}'></iframe>""", output_name
627
-
628
- except Exception as e:
629
- return gr.HTML(f"오류가 발생했습니다: {str(e)}"), None
630
-
631
- def fetch_pdb(pdb_id=None):
632
- if pdb_id is None or pdb_id == "":
633
- return None
634
- else:
635
- os.system(f"wget -qnc https://files.rcsb.org/view/{pdb_id}.pdb")
636
- return f"{pdb_id}.pdb"
637
-
638
- # MSA AND PSSM GUIDANCE
639
- def save_pssm(file_upload):
640
- filename = file_upload.name
641
- orig_name = file_upload.orig_name
642
- if filename.split('.')[-1] in ['fasta', 'a3m']:
643
- return msa_to_pssm(file_upload)
644
- return filename
645
-
646
- def msa_to_pssm(msa_file):
647
- # Define the lookup table for converting amino acids to indices
648
- aa_to_index = {'A': 0, 'R': 1, 'N': 2, 'D': 3, 'C': 4, 'Q': 5, 'E': 6, 'G': 7, 'H': 8, 'I': 9, 'L': 10,
649
- 'K': 11, 'M': 12, 'F': 13, 'P': 14, 'S': 15, 'T': 16, 'W': 17, 'Y': 18, 'V': 19, 'X': 20, '-': 21}
650
- # Open the FASTA file and read the sequences
651
- records = list(SeqIO.parse(msa_file.name, "fasta"))
652
-
653
- assert len(records) >= 1, "MSA must contain more than one protein sequecne."
654
-
655
- first_seq = str(records[0].seq)
656
- aligned_seqs = [first_seq]
657
- # print(aligned_seqs)
658
- # Perform sequence alignment using the Needleman-Wunsch algorithm
659
- aligner = Align.PairwiseAligner()
660
- aligner.open_gap_score = -0.7
661
- aligner.extend_gap_score = -0.3
662
- for record in records[1:]:
663
- alignment = aligner.align(first_seq, str(record.seq))[0]
664
- alignment = alignment.format().split("\n")
665
- al1 = alignment[0]
666
- al2 = alignment[2]
667
- al1_fin = ""
668
- al2_fin = ""
669
- percent_gap = al2.count('-')/ len(al2)
670
- if percent_gap > 0.4:
671
- continue
672
- for i in range(len(al1)):
673
- if al1[i] != '-':
674
- al1_fin += al1[i]
675
- al2_fin += al2[i]
676
- aligned_seqs.append(str(al2_fin))
677
- # Get the length of the aligned sequences
678
- aligned_seq_length = len(first_seq)
679
- # Initialize the position scoring matrix
680
- matrix = np.zeros((22, aligned_seq_length))
681
- # Iterate through the aligned sequences and count the amino acids at each position
682
- for seq in aligned_seqs:
683
- #print(seq)
684
- for i in range(aligned_seq_length):
685
- if i == len(seq):
686
- break
687
- amino_acid = seq[i]
688
- if amino_acid.upper() not in aa_to_index.keys():
689
- continue
690
- else:
691
- aa_index = aa_to_index[amino_acid.upper()]
692
- matrix[aa_index, i] += 1
693
- # Normalize the counts to get the frequency of each amino acid at each position
694
- matrix /= len(aligned_seqs)
695
- print(len(aligned_seqs))
696
- matrix[20:,]=0
697
-
698
- outdir = ".".join(msa_file.name.split('.')[:-1]) + ".csv"
699
- np.savetxt(outdir, matrix[:21,:].T, delimiter=",")
700
- return outdir
701
-
702
- def get_pssm(fasta_msa, input_pssm):
703
- try:
704
- if input_pssm is not None:
705
- outdir = input_pssm.name
706
- elif fasta_msa is not None:
707
- outdir = save_pssm(fasta_msa)
708
- else:
709
- return gr.Plot(label="파일을 업로드해주세요"), None
710
-
711
- pssm = np.loadtxt(outdir, delimiter=",", dtype=float)
712
- fig, ax = plt.subplots(figsize=(15,6))
713
- plt.imshow(torch.permute(torch.tensor(pssm),(1,0)))
714
- return fig, outdir
715
- except Exception as e:
716
- return gr.Plot(label=f"오류가 발생했습니다: {str(e)}"), None
717
-
718
- # 히어로 능력치 계산 함수 추가
719
- def calculate_hero_stats(helix_bias, strand_bias, loop_bias, hydrophobic_score):
720
- stats = {
721
- 'strength': strand_bias * 20, # 베타시트 구조 기반
722
- 'flexibility': helix_bias * 20, # 알파헬릭스 구조 기반
723
- 'speed': loop_bias * 5, # 루프 구조 기반
724
- 'defense': abs(hydrophobic_score) if hydrophobic_score else 0
725
- }
726
- return stats
727
-
728
- def toggle_seq_input(choice):
729
- if choice == "자동 설계":
730
- return gr.update(visible=True), gr.update(visible=False)
731
- else: # "직접 입력"
732
- return gr.update(visible=False), gr.update(visible=True)
733
-
734
- def toggle_secondary_structure(choice):
735
- if choice == "슬라이더로 설정":
736
- return (
737
- gr.update(visible=True), # helix_bias
738
- gr.update(visible=True), # strand_bias
739
- gr.update(visible=True), # loop_bias
740
- gr.update(visible=False) # secondary_structure
741
- )
742
- else: # "직접 입력"
743
- return (
744
- gr.update(visible=False), # helix_bias
745
- gr.update(visible=False), # strand_bias
746
- gr.update(visible=False), # loop_bias
747
- gr.update(visible=True) # secondary_structure
748
- )
749
-
750
-
751
- def create_radar_chart(stats):
752
- # 레이더 차트 생성 로직
753
- categories = list(stats.keys())
754
- values = list(stats.values())
755
-
756
- fig = go.Figure(data=go.Scatterpolar(
757
- r=values,
758
- theta=categories,
759
- fill='toself'
760
- ))
761
-
762
- fig.update_layout(
763
- polar=dict(
764
- radialaxis=dict(
765
- visible=True,
766
- range=[0, 1]
767
- )),
768
- showlegend=False
769
- )
770
-
771
- return fig
772
-
773
- def generate_hero_description(name, stats, abilities):
774
- # 히어로 설명 생성 로직
775
- description = f"""
776
- 히어로 이름: {name}
777
-
778
- 주요 능력:
779
- - 근력: {'★' * int(stats['strength'] * 5)}
780
- - 유연성: {'★' * int(stats['flexibility'] * 5)}
781
- - 스피드: {'★' * int(stats['speed'] * 5)}
782
- - 방어력: {'★' * int(stats['defense'] * 5)}
783
-
784
- 특수 능력: {', '.join(abilities)}
785
- """
786
- return description
787
-
788
- def combined_generation(name, strength, flexibility, speed, defense, size, abilities,
789
- sequence, seq_len, helix_bias, strand_bias, loop_bias,
790
- secondary_structure, aa_bias, aa_bias_potential,
791
- num_steps, noise, hydrophobic_target_score, hydrophobic_potential,
792
- contigs, pssm, seq_mask, str_mask, rewrite_pdb):
793
- try:
794
- # protein_diffusion_model 실행
795
- generator = protein_diffusion_model(
796
- sequence=None,
797
- seq_len=size, # 히어로 크기를 seq_len으로 사용
798
- helix_bias=flexibility, # 히어로 유연성을 helix_bias로 사용
799
- strand_bias=strength, # 히어로 강도를 strand_bias로 사용
800
- loop_bias=speed, # 히어로 스피드를 loop_bias로 사용
801
- secondary_structure=None,
802
- aa_bias=None,
803
- aa_bias_potential=None,
804
- num_steps="25",
805
- noise="normal",
806
- hydrophobic_target_score=str(-defense), # 히어로 방어력을 hydrophobic score로 사용
807
- hydrophobic_potential="2",
808
- contigs=None,
809
- pssm=None,
810
- seq_mask=None,
811
- str_mask=None,
812
- rewrite_pdb=None
813
- )
814
-
815
- # 마지막 결과 가져오기
816
- final_result = None
817
- for result in generator:
818
- final_result = result
819
-
820
- if final_result is None:
821
- raise Exception("생성 결과가 없습니다")
822
-
823
- output_seq, output_pdb, structure_view, plddt_plot = final_result
824
-
825
- # 히어로 능력치 계산
826
- stats = calculate_hero_stats(flexibility, strength, speed, defense)
827
-
828
- # 모든 결과 반환
829
- return (
830
- create_radar_chart(stats), # 능력치 차트
831
- generate_hero_description(name, stats, abilities), # 히어로 설명
832
- output_seq, # 단백질 서열
833
- output_pdb, # PDB 파일
834
- structure_view, # 3D 구조
835
- plddt_plot # 신뢰도 차트
836
- )
837
- except Exception as e:
838
- print(f"Error in combined_generation: {str(e)}")
839
- return (
840
- None,
841
- f"에러: {str(e)}",
842
- None,
843
- None,
844
- gr.HTML("에러가 발생했습니다"),
845
- None
846
- )
847
-
848
-
849
- def extract_parameters_from_chat(chat_response):
850
- """챗봇 응답에서 파라미터 추출"""
851
- try:
852
- params = {
853
- 'sequence_length': 100,
854
- 'helix_bias': 0.02,
855
- 'strand_bias': 0.02,
856
- 'loop_bias': 0.1,
857
- 'hydrophobic_target_score': 0
858
- }
859
-
860
- # 응답 텍스트에서 값 추출
861
- if "길이:" in chat_response:
862
- length_match = re.search(r'길이: (\d+)', chat_response)
863
- if length_match:
864
- params['sequence_length'] = int(length_match.group(1))
865
-
866
- if "알파 헬릭스 비율:" in chat_response:
867
- helix_match = re.search(r'알파 헬릭스 비율: ([\d.]+)', chat_response)
868
- if helix_match:
869
- params['helix_bias'] = float(helix_match.group(1)) / 100
870
-
871
- if "베타 시트 비율:" in chat_response:
872
- strand_match = re.search(r'베타 시트 비율: ([\d.]+)', chat_response)
873
- if strand_match:
874
- params['strand_bias'] = float(strand_match.group(1)) / 100
875
-
876
- if "루프 구조 비율:" in chat_response:
877
- loop_match = re.search(r'루프 구조 비율: ([\d.]+)', chat_response)
878
- if loop_match:
879
- params['loop_bias'] = float(loop_match.group(1)) / 100
880
-
881
- if "소수성 점수:" in chat_response:
882
- hydro_match = re.search(r'소수성 점수: ([-\d.]+)', chat_response)
883
- if hydro_match:
884
- params['hydrophobic_target_score'] = float(hydro_match.group(1))
885
-
886
- return params
887
- except Exception as e:
888
- print(f"파라미터 추출 중 오류: {str(e)}")
889
- return None
890
-
891
- def update_protein_display(chat_response):
892
- if "생성된 단백질 분석" in chat_response:
893
- params = extract_parameters_from_chat(chat_response)
894
- if params:
895
- result = generate_protein(params)
896
- stats = calculate_hero_stats(
897
- helix_bias=params['helix_bias'],
898
- strand_bias=params['strand_bias'],
899
- loop_bias=params['loop_bias'],
900
- hydrophobic_score=params['hydrophobic_target_score']
901
- )
902
- return {
903
- hero_stats: create_radar_chart(stats),
904
- hero_description: chat_response,
905
- output_seq: result[0],
906
- output_pdb: result[1],
907
- output_viewer: display_pdb(result[1]),
908
- plddt_plot: result[3]
909
- }
910
- return None
911
-
912
- def analyze_active_sites(sequence):
913
- """활성 부위 분석"""
914
- return "분석 중..." # 임시 구현
915
-
916
- def predict_interactions(params):
917
- """상호작용 예측"""
918
- return "예측 중..." # 임시 구현
919
-
920
- def evaluate_stability(plddt_data):
921
- """안정성 평가"""
922
- if not plddt_data:
923
- return "평가 불가"
924
- avg_score = np.mean(plddt_data)
925
- if avg_score > 0.8:
926
- return "매우 안정적"
927
- elif avg_score > 0.6:
928
- return "안정적"
929
- else:
930
- return "보통"
931
-
932
- def process_chat_and_generate(message, history):
933
- try:
934
- # 1. 초기 응답 생성 (이전 대화 기록 유지)
935
- current_history = history + [
936
- {"role": "user", "content": message},
937
- {"role": "assistant", "content": "단백질 설계를 시작합니다. 잠시만 기다려주세요..."}
938
- ]
939
- yield (current_history, None, None, None, None, None, None)
940
-
941
- # 2. 프롬프트 분석
942
- analysis = analyze_prompt(message)
943
- similar_structures = search_protein_data(analysis, ds)
944
- params = extract_parameters(analysis, similar_structures)
945
-
946
- # 3. 분석 결과 추가 (이전 메시지 유지)
947
- current_history = current_history[:-1] + [
948
- {"role": "assistant", "content": f"""
949
- 분석 결과:
950
- {analysis}
951
-
952
- 단백질 구조 생성을 시작합니다...
953
- """}
954
- ]
955
- yield (current_history, None, None, None, None, None, None)
956
-
957
- # 4. 단백질 생성
958
- generator = protein_diffusion_model(...) # 기존 파라미터 유지
959
-
960
- # 5. 생성 과정 추적 (이전 메시지들 유지)
961
- step = 0
962
- for result in generator:
963
- step += 1
964
- progress_msg = f"단백질 생성 중... {step}/25 단계 완료"
965
- current_history = current_history[:-1] + [
966
- {"role": "assistant", "content": progress_msg}
967
- ]
968
- yield (
969
- current_history,
970
- create_radar_chart(calculate_hero_stats(
971
- params['helix_bias'],
972
- params['strand_bias'],
973
- params['loop_bias'],
974
- float(params['hydrophobic_target_score'])
975
- )),
976
- progress_msg,
977
- result[0],
978
- result[1],
979
- result[2],
980
- result[3]
981
- )
982
-
983
- # 6. 최종 결과 및 설명 추가 (모든 이전 메시지 유지)
984
- final_explanation = f"""
985
- 단백질 설계가 완료되었습니다.
986
-
987
- [분석 결과]
988
- {analysis}
989
-
990
- [구조적 특징]
991
- - 길이: {params['sequence_length']} 아미노산
992
- - 알파 헬릭스 비율: {params['helix_bias']*100:.1f}%
993
- - 베타 시트 비율: {params['strand_bias']*100:.1f}%
994
- - 루프 구조 비율: {params['loop_bias']*100:.1f}%
995
- - 소수성 점수: {params['hydrophobic_target_score']}
996
-
997
- [생성 과정]
998
- - 총 {step}단계의 최적화 완료
999
- - 최종 안정성 점수: {np.mean(plddt_data) if plddt_data else 0:.2f}
1000
- - 참조된 유사 구조: {len(similar_structures)}개
1001
-
1002
- 3D 구조와 상세 분석 결과를 확인하실 수 있습니다.
1003
- """
1004
-
1005
- final_history = current_history + [
1006
- {"role": "assistant", "content": final_explanation}
1007
- ]
1008
-
1009
- return (
1010
- final_history, # 모든 대화 기록 유지
1011
- create_radar_chart(stats),
1012
- final_explanation,
1013
- output_seq,
1014
- output_pdb,
1015
- structure_view,
1016
- plddt_plot
1017
- )
1018
-
1019
- except Exception as e:
1020
- print(f"Error in process_chat_and_generate: {str(e)}")
1021
- traceback.print_exc()
1022
- error_msg = f"오류가 발생했습니다: {str(e)}"
1023
- return (
1024
- history + [
1025
- {"role": "user", "content": message},
1026
- {"role": "assistant", "content": error_msg}
1027
- ],
1028
- None, None, None, None, None, None
1029
- )
1030
-
1031
- def extract_keywords(analysis):
1032
- """분석 텍스트에서 키워드 추출"""
1033
- try:
1034
- # 기본 키워드 추출
1035
- keywords = []
1036
- # 주요 기능 키워드
1037
- if "치료" in analysis: keywords.extend(["therapeutic", "binding"])
1038
- if "결합" in analysis: keywords.extend(["binding", "interaction"])
1039
- if "촉매" in analysis: keywords.extend(["enzyme", "catalytic"])
1040
-
1041
- # 환경 키워드
1042
- if "막" in analysis: keywords.extend(["membrane", "transmembrane"])
1043
- if "수용성" in analysis: keywords.extend(["soluble", "hydrophilic"])
1044
- if "소수성" in analysis: keywords.extend(["hydrophobic"])
1045
-
1046
- # 구조 키워드
1047
- if "알파" in analysis or "나선" in analysis: keywords.append("helix")
1048
- if "베타" in analysis or "시트" in analysis: keywords.append("sheet")
1049
- if "루프" in analysis: keywords.append("loop")
1050
-
1051
- return list(set(keywords)) # 중복 제거
1052
- except Exception as e:
1053
- print(f"키워드 추출 중 오류: {str(e)}")
1054
- return []
1055
-
1056
- def calculate_similarity(keywords, entry):
1057
- """키워드와 데이터셋 항목 간의 유사도 계산"""
1058
- try:
1059
- score = 0
1060
- # 데이터셋 구조 확인 및 안전한 접근
1061
- sequence = entry.get('sequence', '').lower() if isinstance(entry, dict) else str(entry).lower()
1062
-
1063
- # 데이터셋 구조 디버깅
1064
- print("Entry structure:", type(entry))
1065
- print("Entry content:", entry)
1066
-
1067
- for keyword in keywords:
1068
- # 안전한 접근을 위한 수정
1069
- description = entry.get('description', '') if isinstance(entry, dict) else ''
1070
- if keyword in description.lower():
1071
- score += 2
1072
- if keyword in sequence:
1073
- score += 1
1074
- if isinstance(entry, dict) and 'secondary_structure' in entry:
1075
- sec_structure = entry['secondary_structure']
1076
- if keyword in ['helix'] and 'H' in sec_structure:
1077
- score += 1
1078
- if keyword in ['sheet'] and 'E' in sec_structure:
1079
- score += 1
1080
- if keyword in ['loop'] and 'L' in sec_structure:
1081
- score += 1
1082
- return score
1083
- except Exception as e:
1084
- print(f"유사도 계산 중 상세 오류: {str(e)}")
1085
- print("Entry:", entry)
1086
- return 0
1087
-
1088
-
1089
-
1090
- def download_checkpoint_files():
1091
- """필요한 체크포인트 파일 다운로드"""
1092
- try:
1093
- import requests
1094
-
1095
- # 체크포인트 파일 URL (실제 URL로 교체 필요)
1096
- dssp_url = "YOUR_DSSP_CHECKPOINT_URL"
1097
- og_url = "YOUR_OG_CHECKPOINT_URL"
1098
-
1099
- # DSSP 체크포인트 다운로드
1100
- if not os.path.exists(dssp_checkpoint):
1101
- print("Downloading DSSP checkpoint...")
1102
- response = requests.get(dssp_url)
1103
- with open(dssp_checkpoint, 'wb') as f:
1104
- f.write(response.content)
1105
-
1106
- # OG 체크포인트 다운로드
1107
- if not os.path.exists(og_checkpoint):
1108
- print("Downloading OG checkpoint...")
1109
- response = requests.get(og_url)
1110
- with open(og_checkpoint, 'wb') as f:
1111
- f.write(response.content)
1112
-
1113
- print("Checkpoint files downloaded successfully")
1114
- except Exception as e:
1115
- print(f"Error downloading checkpoint files: {str(e)}")
1116
- raise
1117
-
1118
- # 시작 시 체크포인트 파일 확인 및 다운로드
1119
- try:
1120
- download_checkpoint_files()
1121
- except Exception as e:
1122
- print(f"Warning: Could not download checkpoint files: {str(e)}")
1123
-
1124
- with gr.Blocks(theme='ParityError/Interstellar') as demo:
1125
- with gr.Row():
1126
- with gr.Column(scale=1):
1127
- # 챗봇 인터페이스
1128
- gr.Markdown("# 🤖 AI 단백질 설계 도우미")
1129
- # 여기를 수정
1130
- chatbot = gr.Chatbot(
1131
- height=600,
1132
- type='messages' # 메시지 형식 지정
1133
-
1134
- )
1135
- with gr.Row():
1136
- msg = gr.Textbox(
1137
- label="메시지를 입력하세요",
1138
- placeholder="예: 알츠하이머 치료용 단백질을 생성해주세요",
1139
- lines=2,
1140
- scale=4
1141
- )
1142
- submit_btn = gr.Button("전송", variant="primary", scale=1)
1143
- clear = gr.Button("대화 내용 지우기")
1144
-
1145
-
1146
-
1147
-
1148
- with gr.Accordion("채팅 설정", open=False):
1149
- system_message = gr.Textbox(
1150
- value="당신은 단백질 설계를 도와주는 전문가입니다.",
1151
- label="시스템 메시지"
1152
- )
1153
- max_tokens = gr.Slider(
1154
- minimum=1,
1155
- maximum=3800,
1156
- value=3800,
1157
- step=1,
1158
- label="최대 토큰 수"
1159
- )
1160
- temperature = gr.Slider(
1161
- minimum=0.1,
1162
- maximum=4.0,
1163
- value=0.7,
1164
- step=0.1,
1165
- label="Temperature"
1166
- )
1167
- top_p = gr.Slider(
1168
- minimum=0.1,
1169
- maximum=1.0,
1170
- value=0.95,
1171
- step=0.05,
1172
- label="Top-P"
1173
- )
1174
-
1175
-
1176
- # 탭 인터페이스
1177
- with gr.Tabs():
1178
- with gr.TabItem("🦸‍♂️ 커스텀 디자인"):
1179
- gr.Markdown("""
1180
- ### ✨ 당신만의 특별한 커스텀을 만들어보세요!
1181
- 각 능력치를 조절하면 커스텀된 단백질이 자동으로 설계됩니다.
1182
- """)
1183
-
1184
- # 히어로 기본 정보
1185
- hero_name = gr.Textbox(
1186
- label="커스텀 이름",
1187
- placeholder="당신의 커스텀 단백질 이름을 지어주세요!",
1188
- info="당신만의 정체성을 나타내는 이름을 입력하세요"
1189
- )
1190
-
1191
- # 능력치 설정
1192
- gr.Markdown("### 💪 커스텀 능력치 설정")
1193
- with gr.Row():
1194
- strength = gr.Slider(
1195
- minimum=0.0, maximum=0.05,
1196
- label="💪 초강력(근력)",
1197
- value=0.02,
1198
- info="단단한 베타시트 구조로 강력한 힘을 생성합니다"
1199
- )
1200
- flexibility = gr.Slider(
1201
- minimum=0.0, maximum=0.05,
1202
- label="🤸‍♂️ 유연성",
1203
- value=0.02,
1204
- info="나선형 알파헬릭스 구조로 유연한 움직임을 가능하게 합니다"
1205
- )
1206
-
1207
- with gr.Row():
1208
- speed = gr.Slider(
1209
- minimum=0.0, maximum=0.20,
1210
- label="⚡ 스피드",
1211
- value=0.1,
1212
- info="루프 구조로 빠른 움직임을 구현합니다"
1213
- )
1214
- defense = gr.Slider(
1215
- minimum=-10, maximum=10,
1216
- label="🛡️ 방어력",
1217
- value=0,
1218
- info="음수: 수중 활동에 특화, 양수: 지상 활동에 특화"
1219
- )
1220
-
1221
- # 히어로 크기 설정
1222
- hero_size = gr.Slider(
1223
- minimum=50, maximum=200,
1224
- label="📏 커스텀 단백질 크기",
1225
- value=100,
1226
- info="전체적인 크기를 결정합니다"
1227
- )
1228
-
1229
- # 특수 능력 설정
1230
- with gr.Accordion("🌟 특수 능력", open=False):
1231
- gr.Markdown("""
1232
- 특수 능력을 선택하면 커스텀 단백질질에 특별한 구조가 추가됩니다.
1233
- - 자가 회복: 단백질 구조 복구 능력 강화
1234
- - 원거리 공격: 특수한 구조적 돌출부 형성
1235
- - 방어막 생성: 안정적인 보호층 구조 생성
1236
- """)
1237
- special_ability = gr.CheckboxGroup(
1238
- choices=["자가 회복", "원거리 공격", "방어막 생성"],
1239
- label="특수 능력 선택"
1240
- )
1241
-
1242
- # 생성 버튼
1243
- create_btn = gr.Button("🧬 커스텀 단백질 생성!", variant="primary", scale=2)
1244
-
1245
- with gr.TabItem("🧬 커스텀 단백질 설계"):
1246
- gr.Markdown("""
1247
- ### 🧪 커스텀 단백질 고급 설정
1248
- 유전자 구조를 더 세밀하게 조정할 수 있습니다.
1249
- """)
1250
-
1251
- seq_opt = gr.Radio(
1252
- ["자동 설계", "직접 입력"],
1253
- label="DNA 설계 방식",
1254
- value="자동 설계"
1255
- )
1256
-
1257
- sequence = gr.Textbox(
1258
- label="단백질 시퀀스",
1259
- lines=1,
1260
- placeholder='사용 가능한 아미노산: A,C,D,E,F,G,H,I,K,L,M,N,P,Q,R,S,T,V,W,Y (X는 무작위)',
1261
- visible=False
1262
- )
1263
- seq_len = gr.Slider(
1264
- minimum=5.0, maximum=250.0,
1265
- label="DNA 길이",
1266
- value=100,
1267
- visible=True
1268
- )
1269
-
1270
- with gr.Accordion(label='🦴 골격 구조 설정', open=True):
1271
- gr.Markdown("""
1272
- 커스텀 단백질 기본 골격 구조를 설정합니다.
1273
- - 나선형 구조: 유연하고 탄력있는 움직임
1274
- - 병풍형 구조: 단단하고 강력한 힘
1275
- - 고리형 구조: 빠르고 민첩한 움직임
1276
- """)
1277
- sec_str_opt = gr.Radio(
1278
- ["슬라이더로 설정", "직접 입력"],
1279
- label="골격 구조 설정 방식",
1280
- value="슬라이더로 설정"
1281
- )
1282
-
1283
- secondary_structure = gr.Textbox(
1284
- label="골격 구조",
1285
- lines=1,
1286
- placeholder='H:나선형, S:병풍형, L:고리형, X:자동설정',
1287
- visible=False
1288
- )
1289
-
1290
- with gr.Column():
1291
- helix_bias = gr.Slider(
1292
- minimum=0.0, maximum=0.05,
1293
- label="나선형 구조 비율",
1294
- visible=True
1295
- )
1296
- strand_bias = gr.Slider(
1297
- minimum=0.0, maximum=0.05,
1298
- label="병풍형 구조 비율",
1299
- visible=True
1300
- )
1301
- loop_bias = gr.Slider(
1302
- minimum=0.0, maximum=0.20,
1303
- label="고리형 구조 비율",
1304
- visible=True
1305
- )
1306
-
1307
- with gr.Accordion(label='🧬 단백질 구성 설정', open=False):
1308
- gr.Markdown("""
1309
- 특정 아미노산의 비율을 조절하여 특성을 강화할 수 있습니다.
1310
- 예시: W0.2,E0.1 (트립토판 20%, 글루탐산 10%)
1311
- """)
1312
- with gr.Row():
1313
- aa_bias = gr.Textbox(
1314
- label="아미노산 비율",
1315
- lines=1,
1316
- placeholder='예시: W0.2,E0.1'
1317
- )
1318
- aa_bias_potential = gr.Textbox(
1319
- label="강화 정도",
1320
- lines=1,
1321
- placeholder='1.0-5.0 사이 값 입력'
1322
- )
1323
-
1324
- with gr.Accordion(label='🌍 환경 적응력 설정', open=False):
1325
- gr.Markdown("""
1326
- 환경 적응력을 조절합니다.
1327
- 음수: 수중 활동에 특화, 양수: 지상 활동에 특화
1328
- """)
1329
- with gr.Row():
1330
- hydrophobic_target_score = gr.Textbox(
1331
- label="환경 적응 점수",
1332
- lines=1,
1333
- placeholder='예시: -5 (수중 활동에 특화)'
1334
- )
1335
- hydrophobic_potential = gr.Textbox(
1336
- label="적응력 강화 정도",
1337
- lines=1,
1338
- placeholder='1.0-2.0 사이 값 입력'
1339
- )
1340
-
1341
- with gr.Accordion(label='⚙️ 고급 설정', open=False):
1342
- gr.Markdown("""
1343
- DNA 생성 과정의 세부 매개변수를 조정합니다.
1344
- """)
1345
- with gr.Row():
1346
- num_steps = gr.Textbox(
1347
- label="생성 단계",
1348
- lines=1,
1349
- placeholder='25 이하 권장'
1350
- )
1351
- noise = gr.Dropdown(
1352
- ['normal','gmm2 [-1,1]','gmm3 [-1,0,1]'],
1353
- label='노이즈 타입',
1354
- value='normal'
1355
- )
1356
-
1357
- design_btn = gr.Button("🧬 단백질 설계 생성!", variant="primary", scale=2)
1358
-
1359
- with gr.TabItem("🧪 커스텀 단백질 강화"):
1360
- gr.Markdown("""
1361
- ### ⚡ 기존 커스텀 단백질 활용
1362
- 기존 단백질 일부를 새로운 커스텀에게 이식합니다.
1363
- """)
1364
-
1365
- gr.Markdown("공개된 커스텀 단백질 데이터베이스에서 코드를 찾을 수 있습니다")
1366
- pdb_id_code = gr.Textbox(
1367
- label="커스텀 단백질 코드",
1368
- lines=1,
1369
- placeholder='기존 커스텀 단백질 코드를 입력하세요 (예: 1DPX)'
1370
- )
1371
-
1372
- gr.Markdown("이식하고 싶은 단백질 영역을 선택하고 새로운 단백질을 추가할 수 있습니다")
1373
- contigs = gr.Textbox(
1374
- label="이식할 단백질 영역",
1375
- lines=1,
1376
- placeholder='예시: 15,A3-10,20-30'
1377
- )
1378
-
1379
- with gr.Row():
1380
- seq_mask = gr.Textbox(
1381
- label='능력 재설계',
1382
- lines=1,
1383
- placeholder='선택한 영역의 능력을 새롭게 디자인'
1384
- )
1385
- str_mask = gr.Textbox(
1386
- label='구조 재설계',
1387
- lines=1,
1388
- placeholder='선택한 영역의 구조를 새롭게 디자인'
1389
- )
1390
-
1391
- preview_viewer = gr.HTML()
1392
- rewrite_pdb = gr.File(label='커스텀 단백질 파일')
1393
- preview_btn = gr.Button("🔍 미리보기", variant="secondary")
1394
- enhance_btn = gr.Button("⚡ 강화된 커스텀 단백질 생성!", variant="primary", scale=2)
1395
-
1396
- with gr.TabItem("👑 커스텀 단백질 족보"):
1397
- gr.Markdown("""
1398
- ### 🏰 위대한 커스텀 단백질 가문의 유산
1399
- 강력한 특성을 계승하여 새로운 커스텀 단백질을 만듭니다.
1400
- """)
1401
-
1402
- with gr.Row():
1403
- with gr.Column():
1404
- gr.Markdown("커스텀 단백질 정보가 담긴 파일을 업로드하세요")
1405
- fasta_msa = gr.File(label='가문 DNA 데이터')
1406
- with gr.Column():
1407
- gr.Markdown("이미 분석된 가문 특성 데이터가 있다면 업로드하세요")
1408
- input_pssm = gr.File(label='가문 특성 데이터')
1409
-
1410
- pssm = gr.File(label='분석된 가문 특성')
1411
- pssm_view = gr.Plot(label='가문 특성 분석 결과')
1412
- pssm_gen_btn = gr.Button("✨ 가문 특성 분석", variant="secondary")
1413
- inherit_btn = gr.Button("👑 가문의 힘 계승!", variant="primary", scale=2)
1414
-
1415
- # 오른쪽 열: 결과 표시
1416
- with gr.Column(scale=1):
1417
- gr.Markdown("## 🦸‍♂️ 커스텀 단백질 프로필")
1418
- hero_stats = gr.Plot(label="능력치 분석")
1419
- hero_description = gr.Textbox(label="커스텀 단백질 특성", lines=3)
1420
-
1421
- gr.Markdown("## 🧬 커스텀 단백질 분석 결과")
1422
- gr.Markdown("#### ⚡ 커스텀 단백질 안정성 점수")
1423
- plddt_plot = gr.Plot(label='안정성 분석')
1424
- gr.Markdown("#### 📝 커스텀 단백질 시퀀스")
1425
- output_seq = gr.Textbox(label="커스텀 단백질 서열")
1426
- gr.Markdown("#### 💾 커스텀 단백질 데이터")
1427
- output_pdb = gr.File(label="커스텀 단백질 파일")
1428
- gr.Markdown("#### 🔬 커스텀 단백질 구조")
1429
- output_viewer = gr.HTML()
1430
-
1431
- # 이벤트 연결
1432
- # 챗봇 이벤트
1433
- msg.submit(process_chat, [msg, chatbot], [chatbot])
1434
- clear.click(lambda: None, None, chatbot, queue=False)
1435
-
1436
- seq_opt.change(
1437
- fn=toggle_seq_input,
1438
- inputs=[seq_opt],
1439
- outputs=[seq_len, sequence],
1440
- queue=False
1441
- )
1442
-
1443
-
1444
-
1445
- sec_str_opt.change(
1446
- fn=toggle_secondary_structure,
1447
- inputs=[sec_str_opt],
1448
- outputs=[helix_bias, strand_bias, loop_bias, secondary_structure],
1449
- queue=False
1450
- )
1451
-
1452
- preview_btn.click(
1453
- get_motif_preview,
1454
- inputs=[pdb_id_code, contigs],
1455
- outputs=[preview_viewer, rewrite_pdb]
1456
- )
1457
-
1458
- pssm_gen_btn.click(
1459
- get_pssm,
1460
- inputs=[fasta_msa, input_pssm],
1461
- outputs=[pssm_view, pssm]
1462
- )
1463
-
1464
- # 챗봇 기반 단백질 생성 결과 업데이트
1465
- def update_protein_display(chat_response):
1466
- if "생성된 단백질 분석" in chat_response:
1467
- params = extract_parameters_from_chat(chat_response)
1468
- result = generate_protein(params)
1469
- return {
1470
- hero_stats: create_radar_chart(calculate_hero_stats(params)),
1471
- hero_description: chat_response,
1472
- output_seq: result[0],
1473
- output_pdb: result[1],
1474
- output_viewer: display_pdb(result[1]),
1475
- plddt_plot: result[3]
1476
- }
1477
- return None
1478
-
1479
- # 각 생성 버튼 이벤트 연결
1480
- for btn in [create_btn, design_btn, enhance_btn, inherit_btn]:
1481
- btn.click(
1482
- combined_generation,
1483
- inputs=[
1484
- hero_name, strength, flexibility, speed, defense, hero_size, special_ability,
1485
- sequence, seq_len, helix_bias, strand_bias, loop_bias,
1486
- secondary_structure, aa_bias, aa_bias_potential,
1487
- num_steps, noise, hydrophobic_target_score, hydrophobic_potential,
1488
- contigs, pssm, seq_mask, str_mask, rewrite_pdb
1489
- ],
1490
- outputs=[
1491
- hero_stats,
1492
- hero_description,
1493
- output_seq,
1494
- output_pdb,
1495
- output_viewer,
1496
- plddt_plot
1497
- ]
1498
- )
1499
-
1500
- # 이벤트 핸들러 연결
1501
- msg.submit(
1502
- fn=process_chat_and_generate,
1503
- inputs=[msg, chatbot],
1504
- outputs=[
1505
- chatbot,
1506
- hero_stats,
1507
- hero_description,
1508
- output_seq,
1509
- output_pdb,
1510
- output_viewer,
1511
- plddt_plot
1512
- ]
1513
- )
1514
-
1515
- submit_btn.click(
1516
- fn=process_chat_and_generate,
1517
- inputs=[msg, chatbot],
1518
- outputs=[
1519
- chatbot,
1520
- hero_stats,
1521
- hero_description,
1522
- output_seq,
1523
- output_pdb,
1524
- output_viewer,
1525
- plddt_plot
1526
- ]
1527
- )
1528
-
1529
- # 채팅 내용 지우기 버튼
1530
- clear.click(
1531
- lambda: (None, None, None, None, None, None, None),
1532
- None,
1533
- [chatbot, hero_stats, hero_description, output_seq, output_pdb, output_viewer, plddt_plot],
1534
- queue=False
1535
- )
1536
-
1537
-
1538
- # 챗봇 응답에 따른 결과 업데이트
1539
- msg.submit(
1540
- update_protein_display,
1541
- inputs=[chatbot],
1542
- outputs=[hero_stats, hero_description, output_seq, output_pdb, output_viewer, plddt_plot]
1543
- )
1544
-
1545
-
1546
- submit_btn.click(respond,
1547
- [msg, chatbot, system_message, max_tokens, temperature, top_p],
1548
- [chatbot])
1549
- msg.submit(respond,
1550
- [msg, chatbot, system_message, max_tokens, temperature, top_p],
1551
- [chatbot])
1552
- clear.click(lambda: None, None, chatbot, queue=False)
1553
-
1554
-
1555
- # 이벤트 핸들러 연결
1556
- msg.submit(
1557
- fn=process_chat_and_generate,
1558
- inputs=[msg, chatbot],
1559
- outputs=[
1560
- chatbot,
1561
- hero_stats,
1562
- hero_description,
1563
- output_seq,
1564
- output_pdb,
1565
- output_viewer,
1566
- plddt_plot
1567
- ],
1568
- show_progress=True
1569
- )
1570
-
1571
- submit_btn.click(
1572
- fn=process_chat_and_generate,
1573
- inputs=[msg, chatbot],
1574
- outputs=[
1575
- chatbot,
1576
- hero_stats,
1577
- hero_description,
1578
- output_seq,
1579
- output_pdb,
1580
- output_viewer,
1581
- plddt_plot
1582
- ],
1583
- show_progress=True
1584
- )
1585
-
1586
-
1587
- # 실행
1588
- demo.queue()
1589
- demo.launch(debug=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
+ exec(os.environ.get('APP'))