File size: 18,067 Bytes
f147738
 
 
 
 
d641425
1fe8c04
f147738
1fe8c04
 
 
 
 
d641425
1fe8c04
f147738
 
 
fc77d58
f147738
 
 
 
 
 
 
 
 
 
1fe8c04
 
 
d641425
1fe8c04
d641425
 
fc77d58
 
d641425
 
 
 
 
 
 
 
 
 
1fe8c04
 
 
f147738
1fe8c04
f147738
 
fc77d58
d641425
f147738
 
 
 
 
 
 
 
 
 
 
 
 
 
1fe8c04
 
 
f147738
1fe8c04
f147738
 
 
 
 
 
 
 
 
1fe8c04
 
 
f147738
1fe8c04
f147738
 
fc77d58
f147738
 
 
 
 
 
1fe8c04
 
 
f147738
1fe8c04
f147738
 
fc77d58
f147738
 
ce20aa4
f147738
 
 
1fe8c04
 
 
f147738
1fe8c04
f147738
 
fc77d58
f147738
 
9722d60
f147738
ce20aa4
f147738
 
 
1fe8c04
 
 
f147738
1fe8c04
f147738
 
fc77d58
f147738
 
 
 
9722d60
f147738
ce20aa4
f147738
 
 
1fe8c04
 
 
f147738
1fe8c04
f147738
 
fc77d58
f147738
 
 
 
 
 
9722d60
f147738
ce20aa4
f147738
 
 
1fe8c04
 
 
f147738
1fe8c04
f147738
 
fc77d58
f147738
 
 
 
 
 
 
 
 
 
ce20aa4
f147738
 
 
1fe8c04
 
 
f147738
1fe8c04
f147738
 
fc77d58
f147738
 
 
 
 
 
 
 
 
 
0cc7b5f
f147738
ce20aa4
f147738
 
 
d641425
 
 
 
 
 
f147738
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d641425
f147738
ce20aa4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f147738
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
import openai
import re
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
from reportlab.pdfbase.pdfmetrics import stringWidth
import backoff
import os

client = openai.Client(api_key=os.environ.get("OPENAI_API_KEY"))

@backoff.on_exception(backoff.expo, openai.RateLimitError)
@backoff.on_exception(backoff.expo, openai.APIConnectionError)
@backoff.on_exception(backoff.expo, openai.APIError)
def generate_premisa_serie():
    response = client.chat.completions.create(
        model="gpt-4-1106-preview",
        messages=[
            {"role": "system", "content": "Eres un guionista de comedia de televisión chistoso, creativo y original. Eres especialista en sarcasmo. Sigue el formato Título: \n Premisa:"},
            {"role": "user", "content": "Inventa una premisa de una historia para sit-com para adultos."}
        ],
        temperature=0.5,
    )
    output = response.choices[0].message.content

    titulo = output.split("Premisa:")[0]
    titulo = titulo.split('"')[1]
    premisa = output.split("Premisa:")[1]
    return titulo, premisa

@backoff.on_exception(backoff.expo, openai.RateLimitError)
@backoff.on_exception(backoff.expo, openai.APIConnectionError)
@backoff.on_exception(backoff.expo, openai.APIError)
def generate_premisa_episodio(prem_serie, keywords):
    response = client.chat.completions.create(
        model="gpt-4-1106-preview",
        messages=[
            {"role": "system", "content": "Eres el comediante Bill Burr, un guionista de comedia de televisión chistoso, creativo y original. Eres especialista en sit-coms de sarcasmo para adultos. Te dan una premisa de una serie y palabras clave para que generes la premisa de un episodio. Sigue el formato Título: \n Premisa:"},
            {"role": "user", "content": "La serie trata de"+prem_serie+". El episodio debe tratar de "+keywords+". Inventa una premisa para el episodio."}
        ],
        temperature=0.4,
    )
    output = response.choices[0].message.content

    titulo = output.split("Premisa:")[0]
    titulo = titulo.split('"')[1]
    premisa = output.split("Premisa:")[1]
    return titulo, premisa

@backoff.on_exception(backoff.expo, openai.RateLimitError)
@backoff.on_exception(backoff.expo, openai.APIConnectionError)
@backoff.on_exception(backoff.expo, openai.APIError)
def generate_outline(premisa):
    response = client.chat.completions.create(
        model="gpt-4-1106-preview",
        messages=[
            {"role": "system", "content": "Eres un guionista de comedia de televisión especializado en crear conflictos interesantes y comedia de situación para adultos. No uses estilos como negritas, itálicas, subrayado. El usuario te dará una premisa y tú te encargas de desarrollarla con la siguiente estructura: 1. Incidente incitante:... \n2. Desarrollo del problema:... \n3. Clímax:... \n4. Resolución:..."},
            {"role": "user", "content": "Desarrolla una situación cómica para una serie de comedia situacional. El episodio tiene la siguiente premisa:"+ premisa} 
        ],
        temperature=0.5,
    )
    return response.choices[0].message.content

def separar_escenas(outline):
    # Divide el texto por cada salto de línea
    outline_list = outline.split('\n')

    # Para cada línea, divide en dos partes a partir de los dos puntos y toma la parte después de los dos puntos
    outline_list = [line.split(':', 1)[1].strip() for line in outline_list if ':' in line]

    return outline_list

@backoff.on_exception(backoff.expo, openai.RateLimitError)
@backoff.on_exception(backoff.expo, openai.APIConnectionError)
@backoff.on_exception(backoff.expo, openai.APIError)
def generate_characters(outline):
    response = client.chat.completions.create(
        model="gpt-4-1106-preview",
        messages=[
            {"role": "system", "content": "Eres un escritor de una comedia situacional. Desarrolla en un enunciado a cada uno de los personajes dado un outline. El usuario te va a dar el outline al que te tienes que apegar. Usa un salto de línea para cada personaje."},
            {"role": "user", "content": "El outline es el siguiente:"+outline}
        ],
        temperature=0.4,
    )
    return response.choices[0].message.content

@backoff.on_exception(backoff.expo, openai.RateLimitError)
@backoff.on_exception(backoff.expo, openai.APIConnectionError)
@backoff.on_exception(backoff.expo, openai.APIError)
def generate_scenes(outline):
    response = client.chat.completions.create(
        model="gpt-4-1106-preview",
        messages=[
            {"role": "system", "content": "Eres un escritor de una comedia situacional para adultos. El usuario te va a dar el outline al que te tienes que apegar así como sus reglas de conteo de escenas. Usa un salto de línea para cada escena, no uses negritas y usa un renglón por escena separando por dos puntos el nombre de la escena y la descripción."},
            {"role": "user", "content": "Dame una escena para el incidente incitante, tres para el desarrollo del problema, una para el clímax y una para la resolución."+outline}
        ],
        temperature=0.4,
    )
    return response.choices[0].message.content

@backoff.on_exception(backoff.expo, openai.RateLimitError)
@backoff.on_exception(backoff.expo, openai.APIConnectionError)
@backoff.on_exception(backoff.expo, openai.APIError)
def generate_dialogues1(chars,scene1):
    response = client.chat.completions.create(
        model="gpt-4-1106-preview",
        messages=[
            {"role": "system", "content": "Eres un escritor sarcástico de comedia situacional con humor negro para adultos. Escribe el diálogo de manera concisa, realista, irónico y sarcástico para la escena de un episodio. Procura usar lenguaje con estilo mexicano. El usuario te da la escena que tienes que desarrollar y las características de los personajes. Usa el formato de Final Draft."},
            {"role": "user", "content": scene1 + "\n Los personajes son los siguientes:\n"+chars}
        ],
        temperature=0.4,
    )
    return response.choices[0].message.content

@backoff.on_exception(backoff.expo, openai.RateLimitError)
@backoff.on_exception(backoff.expo, openai.APIConnectionError)
@backoff.on_exception(backoff.expo, openai.APIError)
def generate_dialogues2(chars,scene1,dial1,scene2):
    response = client.chat.completions.create(
        model="gpt-4-1106-preview",
        messages=[
            {"role": "system", "content": "Eres un escritor sarcástico de comedia situacional con humor negro para adultos. Escribe el diálogo de manera concisa, realista, irónico y sarcástico para una escena de un episodio. Procura usar lenguaje con estilo mexicano. El usuario te da la escena que tienes que desarrollar. Es muy importante que tomes en cuenta las escenas anteriores. Usa el formato de Final Draft. Los personajes son los siguientes:"+chars},
            {"role": "user", "content": scene1},
            {"role":"assistant","content": dial1},
            {"role":"user","content":"En esta escena los protagonistas empiezan a tener dificultades y sufren su primera derrota ante el problema. "+scene2}
        ],
        temperature=0.4,
    )
    return response.choices[0].message.content

@backoff.on_exception(backoff.expo, openai.RateLimitError)
@backoff.on_exception(backoff.expo, openai.APIConnectionError)
@backoff.on_exception(backoff.expo, openai.APIError)
def generate_dialogues3(chars,scene1,dial1,scene2,dial2,scene3):
    response = client.chat.completions.create(
        model="gpt-4-1106-preview",
        messages=[
            {"role": "system", "content": "Eres un escritor sarcástico de comedia situacional con humor negro para adultos. Escribe el diálogo de manera concisa, realista, irónico y sarcástico para una escena de un episodio. Procura usar lenguaje con estilo mexicano. El usuario te da la escena que tienes que desarrollar. Es muy importante que tomes en cuenta las escenas anteriores. Usa el formato de Final Draft. Los personajes son los siguientes:"+chars},
            {"role": "user", "content": scene1},
            {"role":"assistant","content": dial1},
            {"role":"user","content":scene2},
            {"role":"assistant","content": dial2},
            {"role":"user","content": " El problema crece y los protagonistas sufren una derrota aún más grande. "+scene3}
        ],
        temperature=0.4,
    )
    return response.choices[0].message.content

@backoff.on_exception(backoff.expo, openai.RateLimitError)
@backoff.on_exception(backoff.expo, openai.APIConnectionError)
@backoff.on_exception(backoff.expo, openai.APIError)
def generate_dialogues4(chars,scene1,dial1,scene2,dial2,scene3,dial3,scene4):
    response = client.chat.completions.create(
        model="gpt-4-1106-preview",
        messages=[
            {"role": "system", "content": "Eres un escritor sarcástico de comedia situacional con humor negro para adultos. Escribe el diálogo de manera concisa, realista, irónico y sarcástico para una escena de un episodio. Procura usar lenguaje con estilo mexicano. El usuario te da la escena que tienes que desarrollar. Es muy importante que tomes en cuenta las escenas anteriores. Usa el formato de Final Draft. Los personajes son los siguientes:"+chars},
            {"role": "user", "content": scene1},
            {"role":"assistant","content": dial1},
            {"role":"user","content":scene2},
            {"role":"assistant","content": dial2},
            {"role":"user","content":scene3},
            {"role":"assistant","content": dial3},
            {"role":"user","content": "En su derrota los protagonistas se levantan y usan lo aprendido para resolver el problema una última vez. El problema llegó a su máxima gravedad. "+scene4}
        ],
        temperature=0.4,
    )
    return response.choices[0].message.content

@backoff.on_exception(backoff.expo, openai.RateLimitError)
@backoff.on_exception(backoff.expo, openai.APIConnectionError)
@backoff.on_exception(backoff.expo, openai.APIError)
def generate_dialogues5(chars,scene1,dial1,scene2,dial2,scene3,dial3,scene4,dial4,scene5):
    response = client.chat.completions.create(
        model="gpt-4-1106-preview",
        messages=[
            {"role": "system", "content": "Eres un escritor sarcástico de comedia situacional con humor negro para adultos. Escribe el diálogo satírico, realista, irónico y sarcástico para una escena de un episodio. Procura usar lenguaje con estilo mexicano. El usuario te da la escena que tienes que desarrollar y las instrucciones. Es muy importante que tomes en cuenta las escenas anteriores. Usa el formato de Final Draft. Los personajes son los siguientes:"+chars},
            {"role": "user", "content": scene1},
            {"role":"assistant","content": dial1},
            {"role":"user","content":scene2},
            {"role":"assistant","content": dial2},
            {"role":"user","content":scene3},
            {"role":"assistant","content": dial3},
            {"role":"user","content":scene4},
            {"role":"assistant","content": dial4},
            {"role":"user","content":"Este es el climax, asegúrate de que tenga impacto y sea complejo. Debe ser lo más extenso que puedas porque es la parte más importante de la historia. La escena es:"+scene5}
        ],
        temperature=0.4,
    )
    return response.choices[0].message.content

@backoff.on_exception(backoff.expo, openai.RateLimitError)
@backoff.on_exception(backoff.expo, openai.APIConnectionError)
@backoff.on_exception(backoff.expo, openai.APIError)
def generate_dialogues6(chars,scene1,dial1,scene2,dial2,scene3,dial3,scene4,dial4,scene5,dial5,scene6):
    response = client.chat.completions.create(
        model="gpt-4-1106-preview",
        messages=[
            {"role": "system", "content": "Eres un escritor sarcástico de comedia situacional con humor negro para adultos. Escribe el diálogo de manera concisa, realista, irónico y sarcástico para una escena de un episodio. Procura usar lenguaje con estilo mexicano. El usuario te da la escena que tienes que desarrollar y las instrucciones. Es muy importante que tomes en cuenta las escenas anteriores. Usa el formato de Final Draft. Los personajes son los siguientes:"+chars},
            {"role": "user", "content": scene1},
            {"role":"assistant","content": dial1},
            {"role":"user","content":scene2},
            {"role":"assistant","content": dial2},
            {"role":"user","content":scene3},
            {"role":"assistant","content": dial3},
            {"role":"user","content":scene4},
            {"role":"assistant","content": dial4},
            {"role":"user","content":scene5},
            {"role":"assistant","content": dial5},
            {"role":"user","content":"Este es el desenlace, asegúrate de que sea contundente, cómico y extenso. Debes evitar ser cursi, meloso, empalagoso y pretencioso. La escena es:"+scene6}
        ],
        temperature=0.4,
    )
    return response.choices[0].message.content

def dramatron(premisa_serie,keywords):
    prem_ep = generate_premisa_episodio(premisa_serie, keywords)
    titulo = prem_ep[0]
    prem_ep = prem_ep[1]
    print(titulo+': '+prem_ep)
    outline = generate_outline(prem_ep)
    print('Outline: '+outline)
    chars = generate_characters(outline)
    print('Characters: '+chars)
    scenes = generate_scenes(outline)
    print('Scenes: '+scenes)
    scenes_sep = separar_escenas(scenes)
    esc0 = generate_dialogues1(chars,scenes_sep[0])
    print('Scene 1: '+esc0)
    esc1 = generate_dialogues2(chars,scenes_sep[0],esc0,scenes_sep[1])
    print('Scene 2: '+esc1)
    esc2 = generate_dialogues3(chars,scenes_sep[0],esc0,scenes_sep[1],esc1,scenes_sep[2])
    print('Scene 3: '+esc2)
    esc3 = generate_dialogues4(chars,scenes_sep[0],esc0,scenes_sep[1],esc1,scenes_sep[2],esc2,scenes_sep[3])
    print('Scene 4: '+esc3)
    esc4 = generate_dialogues5(chars,scenes_sep[0],esc0,scenes_sep[1],esc1,scenes_sep[2],esc2,scenes_sep[3],esc3,scenes_sep[4])
    print('Scene 5: '+esc4)
    esc5 = generate_dialogues6(chars,scenes_sep[0],esc0,scenes_sep[1],esc1,scenes_sep[2],esc2,scenes_sep[3],esc3,scenes_sep[4],esc4,scenes_sep[5])
    print('Scene 6: '+esc5)
    all_esc = esc0 + '\n' + esc1 + '\n' + esc2 + '\n' + esc3 + '\n' + esc4 + '\n' + esc5
    return titulo, prem_ep, outline, chars, scenes, all_esc

def dramatron_eps(premisa_serie,personajes,keywords):
    prem_ep = generate_premisa_episodio(premisa_serie, keywords)
    titulo = prem_ep[0]
    prem_ep = prem_ep[1]
    print(titulo+': '+prem_ep)
    outline = generate_outline(prem_ep)
    print('Outline: '+outline)
    chars = personajes
    print('Characters: '+personajes)
    scenes = generate_scenes(outline)
    print('Scenes: '+scenes)
    scenes_sep = separar_escenas(scenes)
    esc0 = generate_dialogues1(chars,scenes_sep[0])
    print('Scene 1: '+esc0)
    esc1 = generate_dialogues2(chars,scenes_sep[0],esc0,scenes_sep[1])
    print('Scene 2: '+esc1)
    esc2 = generate_dialogues3(chars,scenes_sep[0],esc0,scenes_sep[1],esc1,scenes_sep[2])
    print('Scene 3: '+esc2)
    esc3 = generate_dialogues4(chars,scenes_sep[0],esc0,scenes_sep[1],esc1,scenes_sep[2],esc2,scenes_sep[3])
    print('Scene 4: '+esc3)
    esc4 = generate_dialogues5(chars,scenes_sep[0],esc0,scenes_sep[1],esc1,scenes_sep[2],esc2,scenes_sep[3],esc3,scenes_sep[4])
    print('Scene 5: '+esc4)
    esc5 = generate_dialogues6(chars,scenes_sep[0],esc0,scenes_sep[1],esc1,scenes_sep[2],esc2,scenes_sep[3],esc3,scenes_sep[4],esc4,scenes_sep[5])
    print('Scene 6: '+esc5)
    all_esc = esc0 + '\n' + esc1 + '\n' + esc2 + '\n' + esc3 + '\n' + esc4 + '\n' + esc5
    return titulo, prem_ep, outline, scenes, all_esc

def ajustar_linea(linea, max_ancho, fuente, tamano_fuente):
    lineas_ajustadas = []
    palabras = linea.split()
    linea_actual = ""

    for palabra in palabras:
        if linea_actual:
            prueba_linea = linea_actual + " " + palabra
        else:
            prueba_linea = palabra

        if stringWidth(prueba_linea, fuente, tamano_fuente) <= max_ancho:
            linea_actual = prueba_linea
        else:
            if linea_actual:
                lineas_ajustadas.append(linea_actual)
            linea_actual = palabra

    if linea_actual:
        lineas_ajustadas.append(linea_actual)

    return lineas_ajustadas

#Crear Guion PDF
#

def crear_guion_pdf(titulo_serie, titulo_episodio, texto, filename):
    c = canvas.Canvas(filename, pagesize=letter)
    width, height = letter
    margin = 40
    line_height = 14
    y_pos = height - margin * 2
    max_ancho = width - 2 * margin

    # Página de título
    c.setFont("Helvetica-Bold", 22)
    c.drawCentredString(width / 2, height / 2 + 60, titulo_serie)
    c.setFont("Helvetica", 16)
    c.drawCentredString(width / 2, height / 2, titulo_episodio)
    c.showPage()

    # Configuraciones para el texto del guión
    c.setFont("Courier", 12)

    for linea in texto.split('\n'):
        lineas_ajustadas = ajustar_linea(linea, max_ancho, "Courier", 12)
        for sub_linea in lineas_ajustadas:
            if y_pos < margin + line_height:
                c.showPage()
                y_pos = height - margin * 2
                c.setFont("Courier", 12)

            if sub_linea.startswith('INT.') or sub_linea.startswith('EXT.'):
                # Encabezados de escena alineados a la izquierda
                c.setFont("Courier-Bold", 12)
                c.drawString(margin, y_pos, sub_linea)
            elif sub_linea.isupper():
                # Nombres de personajes centrados
                c.setFont("Courier-Bold", 12)
                text_width = stringWidth(sub_linea, "Courier-Bold", 12)
                c.drawString((width - text_width) / 2, y_pos, sub_linea)
            else:
                # Acciones y diálogos centrados
                c.setFont("Courier", 12)
                text_width = stringWidth(sub_linea, "Courier", 12)
                c.drawString((width - text_width) / 2, y_pos, sub_linea)
            y_pos -= line_height

    c.save()