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()