ManMenGon commited on
Commit
a52cd62
·
verified ·
1 Parent(s): d1c63e4

Upload 5 files

Browse files
Files changed (5) hide show
  1. README.md +75 -14
  2. app.py +141 -0
  3. requirements.txt +0 -0
  4. semillas.json +12 -0
  5. translate_to_geneforgelang.py +49 -0
README.md CHANGED
@@ -1,14 +1,75 @@
1
- ---
2
- title: GeneForgeLang
3
- emoji:
4
- colorFrom: gray
5
- colorTo: red
6
- sdk: gradio
7
- sdk_version: 5.25.2
8
- app_file: app.py
9
- pinned: false
10
- license: mit
11
- short_description: Symbolic-to-Sequence Protein Design Toolkit
12
- ---
13
-
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🧬 GeneForgeLang: Symbolic-to-Sequence Protein Design Toolkit
2
+
3
+ GeneForgeLang is a symbolic language and toolset for generative biology. It connects high-level biological design intentions to low-level amino acid sequences via AI, rules, and natural language.
4
+
5
+ ---
6
+
7
+ ## 🚀 Features
8
+
9
+ | Module | Description |
10
+ |----------------------------|-------------|
11
+ | 🧠 Phrase → Protein | Generate realistic protein sequences from symbolic phrases |
12
+ | 🧪 Protein → Phrase | Infer functional motifs from amino acid sequences |
13
+ | 📖 Phrase → Description | Translate symbolic design into scientific English |
14
+ | 🧬 Mutate Protein | Generate variants of proteins from the same symbolic seed |
15
+ | 📦 Export to FASTA | Download generated proteins for downstream use |
16
+ | 📊 Analyze Protein | Visualize amino acid composition as bar plot |
17
+ | 📚 Symbolic Language | GeneForgeLang syntax allows structured protein definitions |
18
+
19
+ ---
20
+
21
+ ## 🧪 Example
22
+
23
+ ### Input Phrase:
24
+ ^p:Dom(Kin)-Mot(NLS)*AcK@147=Localize(Nucleus)
25
+
26
+ yaml
27
+ Copiar
28
+ Editar
29
+
30
+ ### Output:
31
+ - Seed: `MKKK`
32
+ - Generated protein: realistic sequence (via ProtGPT2)
33
+ - Properties: length, charge, MW
34
+ - Description: *“This protein contains a kinase domain, a nuclear localization signal, and lysine acetylation at a specific position.”*
35
+ - Export: `.fasta` format
36
+ - Graph: bar plot of amino acid composition
37
+
38
+ ---
39
+
40
+ ## ▶️ How to Use
41
+
42
+ 1. Clone this repo
43
+ 2. Install dependencies:
44
+ ```bash
45
+ pip install -r requirements.txt
46
+ Launch the interface:
47
+
48
+ bash
49
+ Copiar
50
+ Editar
51
+ python app.py
52
+ Navigate to:
53
+
54
+ cpp
55
+ Copiar
56
+ Editar
57
+ http://127.0.0.1:7860
58
+ 📁 Repository Structure
59
+
60
+ File Description
61
+ app.py Main UI app with all functionality
62
+ semillas.json Phrase-to-seed dictionary
63
+ translate_to_geneforgelang.py Reverse translator
64
+ README.md This file
65
+ requirements.txt Python dependencies
66
+ 🧠 Developed by
67
+ Fundación de Neurociencias
68
+ Licensed under the MIT License
69
+
70
+ Join us in shaping symbolic bio-AI.
71
+
72
+ yaml
73
+ Copiar
74
+ Editar
75
+
app.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from transformers import AutoTokenizer, AutoModelForCausalLM
3
+ import torch
4
+ import json
5
+ import re
6
+ import tempfile
7
+
8
+ # Load symbolic phrase dictionary
9
+ with open("semillas.json", "r", encoding="utf-8") as f:
10
+ diccionario_semillas = json.load(f)
11
+
12
+ def phrase_to_seed(phrase):
13
+ phrase = phrase.lower()
14
+ for key, seed in diccionario_semillas.items():
15
+ if key.lower() in phrase:
16
+ return seed
17
+ return "M"
18
+
19
+ tokenizer = AutoTokenizer.from_pretrained("nferruz/ProtGPT2", do_lower_case=False)
20
+ tokenizer.pad_token = tokenizer.eos_token
21
+ model = AutoModelForCausalLM.from_pretrained("nferruz/ProtGPT2")
22
+
23
+ def generate_protein_and_props(phrase):
24
+ seed = phrase_to_seed(phrase)
25
+ inputs = tokenizer(seed, return_tensors="pt", padding=True)
26
+ input_ids = inputs["input_ids"]
27
+ attention_mask = inputs.get("attention_mask", torch.ones_like(input_ids))
28
+
29
+ with torch.no_grad():
30
+ output = model.generate(
31
+ input_ids=input_ids,
32
+ attention_mask=attention_mask,
33
+ max_length=100,
34
+ min_length=20,
35
+ do_sample=True,
36
+ top_k=50,
37
+ temperature=0.9,
38
+ pad_token_id=tokenizer.eos_token_id,
39
+ num_return_sequences=1
40
+ )
41
+
42
+ seq = tokenizer.decode(output[0], skip_special_tokens=True)
43
+
44
+ # Calculate properties
45
+ length = len(seq)
46
+ aa_count = {aa: seq.count(aa) for aa in "ACDEFGHIKLMNPQRSTVWY"}
47
+ charge = sum([aa_count.get(a, 0) for a in "KR"]) - sum([aa_count.get(a, 0) for a in "DE"])
48
+ mw = sum([aa_count[a]*w for a, w in {
49
+ "A": 89.1, "C": 121.2, "D": 133.1, "E": 147.1, "F": 165.2,
50
+ "G": 75.1, "H": 155.2, "I": 131.2, "K": 146.2, "L": 131.2,
51
+ "M": 149.2, "N": 132.1, "P": 115.1, "Q": 146.2, "R": 174.2,
52
+ "S": 105.1, "T": 119.1, "V": 117.1, "W": 204.2, "Y": 181.2
53
+ }.items()])
54
+
55
+ props = f"🧪 Seed: {seed}\n🧬 Protein: {seq}\n\n🔬 Properties:\n- Length: {length} aa\n- Charge: {charge}\n- MW: {mw:.1f} Da"
56
+
57
+ # Save to FASTA
58
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".fasta", mode="w", encoding="utf-8") as f:
59
+ f.write(f">Generated_Protein\n{seq}\n")
60
+ fasta_path = f.name
61
+
62
+ return props, fasta_path
63
+
64
+ def sequence_to_phrase(seq):
65
+ seq = seq.upper()
66
+ tags = []
67
+ if re.search(r"^M*K{3,}", seq):
68
+ tags.append("Dom(Kin)")
69
+ if re.search(r"[RK]{3,}", seq):
70
+ tags.append("Mot(NLS)")
71
+ if len(re.findall(r"E", seq)) >= 5 or "DEG" in seq:
72
+ tags.append("Mot(PEST)")
73
+ if re.search(r"KQAK|QAK", seq):
74
+ tags.append("*AcK@X")
75
+ if re.search(r"[RST]P", seq):
76
+ tags.append("*P@X")
77
+ if "PRKRK" in seq or "PKKKRKV" in seq:
78
+ tags.append("Localize(Nucleus)")
79
+ if re.search(r"(AILFL|LAGGAV|LVLL|AAVL)", seq):
80
+ tags.append("Localize(Membrane)")
81
+ return "^p:" + "-".join(sorted(set(tags))) if tags else "// No symbolic motifs found"
82
+
83
+ def phrase_to_description(phrase):
84
+ phrase = phrase.replace("^p:", "")
85
+ fragments = phrase.split("-")
86
+ translation = {
87
+ "Dom(Kin)": "a kinase domain",
88
+ "Mot(NLS)": "a nuclear localization signal",
89
+ "Mot(PEST)": "a PEST motif indicating protein degradation",
90
+ "*AcK@X": "lysine acetylation at a specific position",
91
+ "*P@X": "a phosphorylation site",
92
+ "Localize(Nucleus)": "localizes to the cell nucleus",
93
+ "Localize(Membrane)": "localizes to the cell membrane"
94
+ }
95
+ phrases = [translation.get(tag, tag) for tag in fragments if tag]
96
+ if not phrases:
97
+ return "No interpretable symbolic elements found."
98
+ return "This protein contains " + ", ".join(phrases[:-1]) + (
99
+ f", and {phrases[-1]}." if len(phrases) > 1 else f"{phrases[0]}.")
100
+
101
+ with gr.Blocks() as demo:
102
+ gr.Markdown("# 🧬 GeneForgeLang AI Tools")
103
+ gr.Markdown("Design, interpret, describe, and export proteins using symbolic language and AI.")
104
+
105
+ with gr.Tab("🧠 Phrase → Protein"):
106
+ inp = gr.Textbox(label="GeneForgeLang Phrase", placeholder="^p:Dom(Kin)-Mot(NLS)*AcK@147")
107
+ out = gr.Textbox(label="Protein + Properties")
108
+ fasta = gr.File(label="Download FASTA")
109
+ btn = gr.Button("Generate")
110
+ btn.click(fn=generate_protein_and_props, inputs=inp, outputs=[out, fasta])
111
+
112
+ with gr.Tab("🧪 Protein → Phrase"):
113
+ inp2 = gr.Textbox(label="Protein Sequence", placeholder="MKKKPRRRDEEGEK...")
114
+ out2 = gr.Textbox(label="Interpreted GeneForgeLang")
115
+ btn2 = gr.Button("Translate")
116
+ btn2.click(fn=sequence_to_phrase, inputs=inp2, outputs=out2)
117
+
118
+
119
+ with gr.Tab("🧬 Mutate Protein"):
120
+ inp4 = gr.Textbox(label="GeneForgeLang Phrase", placeholder="^p:Dom(Kin)-Mot(NLS)*AcK@147")
121
+ out4 = gr.Textbox(label="Mutated Protein")
122
+ btn4 = gr.Button("Mutate")
123
+ btn4.click(fn=generate_protein_and_props, inputs=inp4, outputs=[out4, gr.File(visible=False)])
124
+
125
+
126
+ with gr.Tab("📊 Analyze Protein"):
127
+ inp5 = gr.Textbox(label="Protein Sequence", placeholder="Paste sequence to analyze")
128
+ out5 = gr.Image(label="Amino Acid Composition")
129
+ btn5 = gr.Button("Analyze")
130
+ def analyze_graph(seq): return generar_composicion_grafico(seq)
131
+ btn5.click(fn=analyze_graph, inputs=inp5, outputs=out5)
132
+
133
+ with gr.Tab("📖 Phrase → Natural Language"):
134
+
135
+ inp3 = gr.Textbox(label="GeneForgeLang Phrase", placeholder="^p:Dom(Kin)-Mot(NLS)*AcK@147")
136
+ out3 = gr.Textbox(label="Scientific Description")
137
+ btn3 = gr.Button("Describe")
138
+ btn3.click(fn=phrase_to_description, inputs=inp3, outputs=out3)
139
+
140
+ if __name__ == "__main__":
141
+ demo.launch()
requirements.txt ADDED
Binary file (78 Bytes). View file
 
semillas.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "Dom(Kin)": "MKKK",
3
+ "Mot(NLS)": "MPRRR",
4
+ "Mot(PEST)": "MDGQL",
5
+ "TF(GATA1)": "MKTFG",
6
+ "*AcK": "MKQAK",
7
+ "*Ac": "MKQAK",
8
+ "*P": "MKRP",
9
+ "*Phos": "MKRP",
10
+ "Localize(Nucleus)": "MPKRK",
11
+ "Localize(Membrane)": "MAIFL"
12
+ }
translate_to_geneforgelang.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import re
3
+
4
+ # Nuevas reglas de reconocimiento con patrones suaves
5
+ def traducir_a_geneforge(secuencia):
6
+ motivos = []
7
+
8
+ # Dom(Kin): 3 o más K seguidos al principio
9
+ if re.search(r"^M*K{3,}", secuencia):
10
+ motivos.append("Dom(Kin)")
11
+
12
+ # Mot(NLS): presencia de varias R o K juntas, típica señal nuclear
13
+ if re.search(r"[RK]{3,}", secuencia):
14
+ motivos.append("Mot(NLS)")
15
+
16
+ # Mot(PEST): alta densidad de E o D (glutámico o aspártico)
17
+ if len(re.findall(r"E", secuencia)) >= 5 or "DEG" in secuencia:
18
+ motivos.append("Mot(PEST)")
19
+
20
+ # *AcK@X: presencia de "KQAK" o "QAK" como motivo de acetilación
21
+ if re.search(r"KQAK|QAK", secuencia):
22
+ motivos.append("*AcK@X")
23
+
24
+ # *P@X: motivos de fosforilación comunes
25
+ if re.search(r"[RST]P", secuencia):
26
+ motivos.append("*P@X")
27
+
28
+ # Localize(Nucleus): presencia de PRKRK, PKKKRKV
29
+ if "PRKRK" in secuencia or "PKKKRKV" in secuencia:
30
+ motivos.append("Localize(Nucleus)")
31
+
32
+ # Localize(Membrane): patrones hidrofóbicos como AILFL o LAGGAV
33
+ if re.search(r"(AILFL|LAGGAV|LVLL|AAVL)", secuencia):
34
+ motivos.append("Localize(Membrane)")
35
+
36
+ if not motivos:
37
+ return "// No se encontraron motivos reconocibles"
38
+
39
+ return "^p:" + "-".join(sorted(set(motivos)))
40
+
41
+ if __name__ == "__main__":
42
+ if len(sys.argv) < 2:
43
+ print("Uso: python traducir_a_geneforgelang_v2.py <secuencia_proteina>")
44
+ sys.exit(1)
45
+
46
+ secuencia = sys.argv[1].upper()
47
+ resultado = traducir_a_geneforge(secuencia)
48
+ print("🔍 GeneForgeLang:")
49
+ print(resultado)