tbdavid2019 commited on
Commit
099c05b
1 Parent(s): 538134f

Upload folder using huggingface_hub

Browse files
Files changed (7) hide show
  1. .env +1 -0
  2. LICENSE +201 -0
  3. PDF2Audio.ipynb +977 -0
  4. README.md +121 -6
  5. app.py +892 -0
  6. logo.png +0 -0
  7. requirements.txt +7 -0
.env ADDED
@@ -0,0 +1 @@
 
 
1
+ OPENAI_API_KEY=sk-proj-4iGRmIxZ6SjeyvdCbZJgT3BlbkFJwUnYutqBPlnIr5fRq5yB
LICENSE ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
PDF2Audio.ipynb ADDED
@@ -0,0 +1,977 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {
6
+ "id": "DrL_MhvI1xPn"
7
+ },
8
+ "source": [
9
+ "# PDF to Audio Converter\n",
10
+ "\n",
11
+ "This code can be used to convert PDFs into audio podcasts, lectures, summaries, and more. It uses OpenAI's GPT models for text generation and text-to-speech conversion.\n",
12
+ "\n",
13
+ "Source: [https://github.com/lamm-mit/PDF2Audio](https://github.com/lamm-mit/PDF2Audio)\n",
14
+ "\n"
15
+ ]
16
+ },
17
+ {
18
+ "cell_type": "code",
19
+ "execution_count": null,
20
+ "metadata": {
21
+ "colab": {
22
+ "base_uri": "https://localhost:8080/"
23
+ },
24
+ "id": "JrPccs_M1qZ9",
25
+ "outputId": "bf90828d-c67c-4cfa-919f-9c434c0a55ec"
26
+ },
27
+ "outputs": [],
28
+ "source": [
29
+ "!pip install loguru gradio promptic pydantic pypdf tenacity openai -q"
30
+ ]
31
+ },
32
+ {
33
+ "cell_type": "code",
34
+ "execution_count": null,
35
+ "metadata": {
36
+ "cellView": "form",
37
+ "colab": {
38
+ "base_uri": "https://localhost:8080/",
39
+ "height": 626
40
+ },
41
+ "id": "nEduHdSD1fE-",
42
+ "outputId": "e450cf4a-f3b9-437f-d7b3-a34d2bc4467c"
43
+ },
44
+ "outputs": [],
45
+ "source": [
46
+ "# @title\n",
47
+ "import concurrent.futures as cf\n",
48
+ "import glob\n",
49
+ "import io\n",
50
+ "import os\n",
51
+ "import time\n",
52
+ "from pathlib import Path\n",
53
+ "from tempfile import NamedTemporaryFile\n",
54
+ "from typing import List, Literal\n",
55
+ "\n",
56
+ "import gradio as gr\n",
57
+ "\n",
58
+ "from loguru import logger\n",
59
+ "from openai import OpenAI\n",
60
+ "from promptic import llm\n",
61
+ "from pydantic import BaseModel, ValidationError\n",
62
+ "from pypdf import PdfReader\n",
63
+ "from tenacity import retry, retry_if_exception_type\n",
64
+ "\n",
65
+ "import re\n",
66
+ "\n",
67
+ "def read_readme():\n",
68
+ " readme_path = Path(\"README.md\")\n",
69
+ " if readme_path.exists():\n",
70
+ " with open(readme_path, \"r\") as file:\n",
71
+ " content = file.read()\n",
72
+ " # Use regex to remove metadata enclosed in -- ... --\n",
73
+ " content = re.sub(r'--.*?--', '', content, flags=re.DOTALL)\n",
74
+ " return content\n",
75
+ " else:\n",
76
+ " return \"README.md not found. Please check the repository for more information.\"\n",
77
+ " \n",
78
+ "# Define multiple sets of instruction templates\n",
79
+ "INSTRUCTION_TEMPLATES = {\n",
80
+ "################# PODCAST ##################\n",
81
+ " \"podcast\": {\n",
82
+ " \"intro\": \"\"\"Your task is to take the input text provided and turn it into an lively, engaging, informative podcast dialogue, in the style of NPR. The input text may be messy or unstructured, as it could come from a variety of sources like PDFs or web pages. \n",
83
+ "\n",
84
+ "Don't worry about the formatting issues or any irrelevant information; your goal is to extract the key points, identify definitions, and interesting facts that could be discussed in a podcast. \n",
85
+ "\n",
86
+ "Define all terms used carefully for a broad audience of listeners.\n",
87
+ "\"\"\",\n",
88
+ " \"text_instructions\": \"First, carefully read through the input text and identify the main topics, key points, and any interesting facts or anecdotes. Think about how you could present this information in a fun, engaging way that would be suitable for a high quality presentation.\",\n",
89
+ " \"scratch_pad\": \"\"\"Brainstorm creative ways to discuss the main topics and key points you identified in the input text. Consider using analogies, examples, storytelling techniques, or hypothetical scenarios to make the content more relatable and engaging for listeners.\n",
90
+ "\n",
91
+ "Keep in mind that your podcast should be accessible to a general audience, so avoid using too much jargon or assuming prior knowledge of the topic. If necessary, think of ways to briefly explain any complex concepts in simple terms.\n",
92
+ "\n",
93
+ "Use your imagination to fill in any gaps in the input text or to come up with thought-provoking questions that could be explored in the podcast. The goal is to create an informative and entertaining dialogue, so feel free to be creative in your approach.\n",
94
+ "\n",
95
+ "Define all terms used clearly and spend effort to explain the background.\n",
96
+ "\n",
97
+ "Write your brainstorming ideas and a rough outline for the podcast dialogue here. Be sure to note the key insights and takeaways you want to reiterate at the end.\n",
98
+ "\n",
99
+ "Make sure to make it fun and exciting. \n",
100
+ "\"\"\",\n",
101
+ " \"prelude\": \"\"\"Now that you have brainstormed ideas and created a rough outline, it's time to write the actual podcast dialogue. Aim for a natural, conversational flow between the host and any guest speakers. Incorporate the best ideas from your brainstorming session and make sure to explain any complex topics in an easy-to-understand way.\n",
102
+ "\"\"\",\n",
103
+ " \"dialog\": \"\"\"Write a very long, engaging, informative podcast dialogue here, based on the key points and creative ideas you came up with during the brainstorming session. Use a conversational tone and include any necessary context or explanations to make the content accessible to a general audience. \n",
104
+ "\n",
105
+ "Never use made-up names for the hosts and guests, but make it an engaging and immersive experience for listeners. Do not include any bracketed placeholders like [Host] or [Guest]. Design your output to be read aloud -- it will be directly converted into audio.\n",
106
+ "\n",
107
+ "Make the dialogue as long and detailed as possible, while still staying on topic and maintaining an engaging flow. Aim to use your full output capacity to create the longest podcast episode you can, while still communicating the key information from the input text in an entertaining way.\n",
108
+ "\n",
109
+ "At the end of the dialogue, have the host and guest speakers naturally summarize the main insights and takeaways from their discussion. This should flow organically from the conversation, reiterating the key points in a casual, conversational manner. Avoid making it sound like an obvious recap - the goal is to reinforce the central ideas one last time before signing off. \n",
110
+ "\n",
111
+ "The podcast should have around 20000 words.\n",
112
+ "\"\"\",\n",
113
+ " },\n",
114
+ "################# MATERIAL DISCOVERY SUMMARY ##################\n",
115
+ " \"SciAgents material discovery summary\": {\n",
116
+ " \"intro\": \"\"\"Your task is to take the input text provided and turn it into a lively, engaging conversation between a professor and a student in a panel discussion that describes a new material. The professor acts like Richard Feynman, but you never mention the name.\n",
117
+ "\n",
118
+ "The input text is the result of a design developed by SciAgents, an AI tool for scientific discovery that has come up with a detailed materials design.\n",
119
+ "\n",
120
+ "Don't worry about the formatting issues or any irrelevant information; your goal is to extract the key points, identify definitions, and interesting facts that could be discussed in a podcast.\n",
121
+ "\n",
122
+ "Define all terms used carefully for a broad audience of listeners.\n",
123
+ "\"\"\",\n",
124
+ " \"text_instructions\": \"First, carefully read through the input text and identify the main topics, key points, and any interesting facts or anecdotes. Think about how you could present this information in a fun, engaging way that would be suitable for a high quality presentation.\",\n",
125
+ " \"scratch_pad\": \"\"\"Brainstorm creative ways to discuss the main topics and key points you identified in the material design summary, especially paying attention to design features developed by SciAgents. Consider using analogies, examples, storytelling techniques, or hypothetical scenarios to make the content more relatable and engaging for listeners.\n",
126
+ "\n",
127
+ "Keep in mind that your description should be accessible to a general audience, so avoid using too much jargon or assuming prior knowledge of the topic. If necessary, think of ways to briefly explain any complex concepts in simple terms.\n",
128
+ "\n",
129
+ "Use your imagination to fill in any gaps in the input text or to come up with thought-provoking questions that could be explored in the podcast. The goal is to create an informative and entertaining dialogue, so feel free to be creative in your approach.\n",
130
+ "\n",
131
+ "Define all terms used clearly and spend effort to explain the background.\n",
132
+ "\n",
133
+ "Write your brainstorming ideas and a rough outline for the podcast dialogue here. Be sure to note the key insights and takeaways you want to reiterate at the end.\n",
134
+ "\n",
135
+ "Make sure to make it fun and exciting. You never refer to the podcast, you just discuss the discovery and you focus on the new material design only.\n",
136
+ "\"\"\",\n",
137
+ " \"prelude\": \"\"\"Now that you have brainstormed ideas and created a rough outline, it's time to write the actual podcast dialogue. Aim for a natural, conversational flow between the host and any guest speakers. Incorporate the best ideas from your brainstorming session and make sure to explain any complex topics in an easy-to-understand way.\n",
138
+ "\"\"\",\n",
139
+ " \"dialog\": \"\"\"Write a very long, engaging, informative dialogue here, based on the key points and creative ideas you came up with during the brainstorming session. The presentation must focus on the novel aspects of the material design, behavior, and all related aspects.\n",
140
+ "\n",
141
+ "Use a conversational tone and include any necessary context or explanations to make the content accessible to a general audience, but make it detailed, logical, and technical so that it has all necessary aspects for listeners to understand the material and its unexpected properties.\n",
142
+ "\n",
143
+ "Remember, this describes a design developed by SciAgents, and this must be explicitly stated for the listeners.\n",
144
+ "\n",
145
+ "Never use made-up names for the hosts and guests, but make it an engaging and immersive experience for listeners. Do not include any bracketed placeholders like [Host] or [Guest]. Design your output to be read aloud -- it will be directly converted into audio.\n",
146
+ "\n",
147
+ "Make the dialogue as long and detailed as possible with great scientific depth, while still staying on topic and maintaining an engaging flow. Aim to use your full output capacity to create the longest podcast episode you can, while still communicating the key information from the input text in an entertaining way.\n",
148
+ "\n",
149
+ "At the end of the dialogue, have the host and guest speakers naturally summarize the main insights and takeaways from their discussion. This should flow organically from the conversation, reiterating the key points in a casual, conversational manner. Avoid making it sound like an obvious recap - the goal is to reinforce the central ideas one last time before signing off.\n",
150
+ "\n",
151
+ "The conversation should have around 20000 words.\n",
152
+ "\"\"\"\n",
153
+ " },\n",
154
+ "################# LECTURE ##################\n",
155
+ " \"lecture\": {\n",
156
+ " \"intro\": \"\"\"You are Professor Richard Feynman. Your task is to develop a script for a lecture. You never mention your name.\n",
157
+ "\n",
158
+ "The material covered in the lecture is based on the provided text. \n",
159
+ "\n",
160
+ "Don't worry about the formatting issues or any irrelevant information; your goal is to extract the key points, identify definitions, and interesting facts that need to be covered in the lecture. \n",
161
+ "\n",
162
+ "Define all terms used carefully for a broad audience of students.\n",
163
+ "\"\"\",\n",
164
+ " \"text_instructions\": \"First, carefully read through the input text and identify the main topics, key points, and any interesting facts or anecdotes. Think about how you could present this information in a fun, engaging way that would be suitable for a high quality presentation.\",\n",
165
+ " \"scratch_pad\": \"\"\"\n",
166
+ "Brainstorm creative ways to discuss the main topics and key points you identified in the input text. Consider using analogies, examples, storytelling techniques, or hypothetical scenarios to make the content more relatable and engaging for listeners.\n",
167
+ "\n",
168
+ "Keep in mind that your lecture should be accessible to a general audience, so avoid using too much jargon or assuming prior knowledge of the topic. If necessary, think of ways to briefly explain any complex concepts in simple terms.\n",
169
+ "\n",
170
+ "Use your imagination to fill in any gaps in the input text or to come up with thought-provoking questions that could be explored in the podcast. The goal is to create an informative and entertaining dialogue, so feel free to be creative in your approach.\n",
171
+ "\n",
172
+ "Define all terms used clearly and spend effort to explain the background.\n",
173
+ "\n",
174
+ "Write your brainstorming ideas and a rough outline for the lecture here. Be sure to note the key insights and takeaways you want to reiterate at the end.\n",
175
+ "\n",
176
+ "Make sure to make it fun and exciting. \n",
177
+ "\"\"\",\n",
178
+ " \"prelude\": \"\"\"Now that you have brainstormed ideas and created a rough outline, it's time to write the actual podcast dialogue. Aim for a natural, conversational flow between the host and any guest speakers. Incorporate the best ideas from your brainstorming session and make sure to explain any complex topics in an easy-to-understand way.\n",
179
+ "\"\"\",\n",
180
+ " \"dialog\": \"\"\"Write a very long, engaging, informative script here, based on the key points and creative ideas you came up with during the brainstorming session. Use a conversational tone and include any necessary context or explanations to make the content accessible to the students.\n",
181
+ "\n",
182
+ "Include clear definitions and terms, and examples. \n",
183
+ "\n",
184
+ "Do not include any bracketed placeholders like [Host] or [Guest]. Design your output to be read aloud -- it will be directly converted into audio.\n",
185
+ "\n",
186
+ "There is only one speaker, you, the professor. Stay on topic and maintaining an engaging flow. Aim to use your full output capacity to create the longest lecture you can, while still communicating the key information from the input text in an engaging way.\n",
187
+ "\n",
188
+ "At the end of the lecture, naturally summarize the main insights and takeaways from the lecture. This should flow organically from the conversation, reiterating the key points in a casual, conversational manner. \n",
189
+ "\n",
190
+ "Avoid making it sound like an obvious recap - the goal is to reinforce the central ideas covered in this lecture one last time before class is over. \n",
191
+ "\n",
192
+ "The lecture should have around 20000 words.\n",
193
+ "\"\"\",\n",
194
+ " },\n",
195
+ "################# SUMMARY ##################\n",
196
+ " \"summary\": {\n",
197
+ " \"intro\": \"\"\"Your task is to develop a summary of a paper. You never mention your name.\n",
198
+ "\n",
199
+ "Don't worry about the formatting issues or any irrelevant information; your goal is to extract the key points, identify definitions, and interesting facts that need to be summarized.\n",
200
+ "\n",
201
+ "Define all terms used carefully for a broad audience.\n",
202
+ "\"\"\",\n",
203
+ " \"text_instructions\": \"First, carefully read through the input text and identify the main topics, key points, and key facts. Think about how you could present this information in an accurate summary.\",\n",
204
+ " \"scratch_pad\": \"\"\"Brainstorm creative ways to present the main topics and key points you identified in the input text. Consider using analogies, examples, or hypothetical scenarios to make the content more relatable and engaging for listeners.\n",
205
+ "\n",
206
+ "Keep in mind that your summary should be accessible to a general audience, so avoid using too much jargon or assuming prior knowledge of the topic. If necessary, think of ways to briefly explain any complex concepts in simple terms. Define all terms used clearly and spend effort to explain the background.\n",
207
+ "\n",
208
+ "Write your brainstorming ideas and a rough outline for the summary here. Be sure to note the key insights and takeaways you want to reiterate at the end.\n",
209
+ "\n",
210
+ "Make sure to make it engaging and exciting. \n",
211
+ "\"\"\",\n",
212
+ " \"prelude\": \"\"\"Now that you have brainstormed ideas and created a rough outline, it is time to write the actual summary. Aim for a natural, conversational flow between the host and any guest speakers. Incorporate the best ideas from your brainstorming session and make sure to explain any complex topics in an easy-to-understand way.\n",
213
+ "\"\"\",\n",
214
+ " \"dialog\": \"\"\"Write a a script here, based on the key points and creative ideas you came up with during the brainstorming session. Use a conversational tone and include any necessary context or explanations to make the content accessible to the the audience.\n",
215
+ "\n",
216
+ "Start your script by stating that this is a summary, referencing the title or headings in the input text. If the input text has no title, come up with a succinct summary of what is covered to open.\n",
217
+ "\n",
218
+ "Include clear definitions and terms, and examples, of all key issues. \n",
219
+ "\n",
220
+ "Do not include any bracketed placeholders like [Host] or [Guest]. Design your output to be read aloud -- it will be directly converted into audio.\n",
221
+ "\n",
222
+ "There is only one speaker, you. Stay on topic and maintaining an engaging flow. \n",
223
+ "\n",
224
+ "Naturally summarize the main insights and takeaways from the summary. This should flow organically from the conversation, reiterating the key points in a casual, conversational manner. \n",
225
+ "\n",
226
+ "The summary should have around 1024 words.\n",
227
+ "\"\"\",\n",
228
+ " },\n",
229
+ "################# SHORT SUMMARY ##################\n",
230
+ " \"short summary\": {\n",
231
+ " \"intro\": \"\"\"Your task is to develop a summary of a paper. You never mention your name.\n",
232
+ "\n",
233
+ "Don't worry about the formatting issues or any irrelevant information; your goal is to extract the key points, identify definitions, and interesting facts that need to be summarized.\n",
234
+ "\n",
235
+ "Define all terms used carefully for a broad audience.\n",
236
+ "\"\"\",\n",
237
+ " \"text_instructions\": \"First, carefully read through the input text and identify the main topics, key points, and key facts. Think about how you could present this information in an accurate summary.\",\n",
238
+ " \"scratch_pad\": \"\"\"Brainstorm creative ways to present the main topics and key points you identified in the input text. Consider using analogies, examples, or hypothetical scenarios to make the content more relatable and engaging for listeners.\n",
239
+ "\n",
240
+ "Keep in mind that your summary should be accessible to a general audience, so avoid using too much jargon or assuming prior knowledge of the topic. If necessary, think of ways to briefly explain any complex concepts in simple terms. Define all terms used clearly and spend effort to explain the background.\n",
241
+ "\n",
242
+ "Write your brainstorming ideas and a rough outline for the summary here. Be sure to note the key insights and takeaways you want to reiterate at the end.\n",
243
+ "\n",
244
+ "Make sure to make it engaging and exciting. \n",
245
+ "\"\"\",\n",
246
+ " \"prelude\": \"\"\"Now that you have brainstormed ideas and created a rough outline, it is time to write the actual summary. Aim for a natural, conversational flow between the host and any guest speakers. Incorporate the best ideas from your brainstorming session and make sure to explain any complex topics in an easy-to-understand way.\n",
247
+ "\"\"\",\n",
248
+ " \"dialog\": \"\"\"Write a a script here, based on the key points and creative ideas you came up with during the brainstorming session. Keep it concise, and use a conversational tone and include any necessary context or explanations to make the content accessible to the the audience.\n",
249
+ "\n",
250
+ "Start your script by stating that this is a summary, referencing the title or headings in the input text. If the input text has no title, come up with a succinct summary of what is covered to open.\n",
251
+ "\n",
252
+ "Include clear definitions and terms, and examples, of all key issues. \n",
253
+ "\n",
254
+ "Do not include any bracketed placeholders like [Host] or [Guest]. Design your output to be read aloud -- it will be directly converted into audio.\n",
255
+ "\n",
256
+ "There is only one speaker, you. Stay on topic and maintaining an engaging flow. \n",
257
+ "\n",
258
+ "Naturally summarize the main insights and takeaways from the short summary. This should flow organically from the conversation, reiterating the key points in a casual, conversational manner. \n",
259
+ "\n",
260
+ "The summary should have around 256 words.\n",
261
+ "\"\"\",\n",
262
+ " },\n",
263
+ "################# PODCAST French ##################\n",
264
+ "\"podcast (French)\": {\n",
265
+ " \"intro\": \"\"\"Votre tâche consiste à prendre le texte fourni et à le transformer en un dialogue de podcast vivant, engageant et informatif, dans le style de NPR. Le texte d'entrée peut être désorganisé ou non structuré, car il peut provenir de diverses sources telles que des fichiers PDF ou des pages web.\n",
266
+ "\n",
267
+ "Ne vous inquiétez pas des problèmes de formatage ou des informations non pertinentes ; votre objectif est d'extraire les points clés, d'identifier les définitions et les faits intéressants qui pourraient être discutés dans un podcast.\n",
268
+ "\n",
269
+ "Définissez soigneusement tous les termes utilisés pour un public large.\n",
270
+ "\"\"\",\n",
271
+ " \"text_instructions\": \"Tout d'abord, lisez attentivement le texte d'entrée et identifiez les principaux sujets, points clés et faits ou anecdotes intéressants. Réfléchissez à la manière dont vous pourriez présenter ces informations de manière amusante et engageante, convenant à une présentation de haute qualité.\",\n",
272
+ " \"scratch_pad\": \"\"\"Réfléchissez à des moyens créatifs pour discuter des principaux sujets et points clés que vous avez identifiés dans le texte d'entrée. Envisagez d'utiliser des analogies, des exemples, des techniques de narration ou des scénarios hypothétiques pour rendre le contenu plus accessible et attrayant pour les auditeurs.\n",
273
+ "\n",
274
+ "Gardez à l'esprit que votre podcast doit être accessible à un large public, donc évitez d'utiliser trop de jargon ou de supposer une connaissance préalable du sujet. Si nécessaire, trouvez des moyens d'expliquer brièvement les concepts complexes en termes simples.\n",
275
+ "\n",
276
+ "Utilisez votre imagination pour combler les lacunes du texte d'entrée ou pour poser des questions stimulantes qui pourraient être explorées dans le podcast. L'objectif est de créer un dialogue informatif et divertissant, donc n'hésitez pas à faire preuve de créativité dans votre approche.\n",
277
+ "\n",
278
+ "Définissez clairement tous les termes utilisés et prenez le temps d'expliquer le contexte.\n",
279
+ "\n",
280
+ "Écrivez ici vos idées de brainstorming et une esquisse générale pour le dialogue du podcast. Assurez-vous de noter les principaux points et enseignements que vous souhaitez réitérer à la fin.\n",
281
+ "\n",
282
+ "Faites en sorte que ce soit amusant et captivant.\n",
283
+ "\"\"\",\n",
284
+ " \"prelude\": \"\"\"Maintenant que vous avez réfléchi à des idées et créé une esquisse générale, il est temps d'écrire le dialogue réel du podcast. Visez un flux naturel et conversationnel entre l'hôte et tout invité. Intégrez les meilleures idées de votre session de brainstorming et assurez-vous d'expliquer tous les sujets complexes de manière compréhensible.\n",
285
+ "\"\"\",\n",
286
+ " \"dialog\": \"\"\"Écrivez ici un dialogue de podcast très long, captivant et informatif, basé sur les points clés et les idées créatives que vous avez développés lors de la session de brainstorming. Utilisez un ton conversationnel et incluez tout contexte ou explication nécessaire pour rendre le contenu accessible à un public général.\n",
287
+ "\n",
288
+ "Ne créez jamais de noms fictifs pour les hôtes et les invités, mais rendez cela engageant et immersif pour les auditeurs. N'incluez pas de marqueurs entre crochets comme [Hôte] ou [Invité]. Conceptionnez votre sortie pour être lue à haute voix – elle sera directement convertie en audio.\n",
289
+ "\n",
290
+ "Faites en sorte que le dialogue soit aussi long et détaillé que possible, tout en restant sur le sujet et en maintenant un flux engageant. Utilisez toute votre capacité de production pour créer l'épisode de podcast le plus long possible, tout en communiquant les informations clés du texte d'entrée de manière divertissante.\n",
291
+ "\n",
292
+ "À la fin du dialogue, l'hôte et les invités doivent naturellement résumer les principales idées et enseignements de leur discussion. Cela doit découler naturellement de la conversation, en réitérant les points clés de manière informelle et conversationnelle. Évitez de donner l'impression qu'il s'agit d'un récapitulatif évident – l'objectif est de renforcer les idées centrales une dernière fois avant de conclure.\n",
293
+ "\n",
294
+ "Le podcast doit comporter environ 20 000 mots.\n",
295
+ "\"\"\",\n",
296
+ "},\n",
297
+ "\n",
298
+ "################# PODCAST GERMAN ##################\n",
299
+ "\"podcast (German)\": {\n",
300
+ " \"intro\": \"\"\"Deine Aufgabe ist es, den bereitgestellten Text in einen lebendigen, fesselnden und informativen Podcast-Dialog im Stil von NPR zu verwandeln. Der Eingabetext kann unstrukturiert oder chaotisch sein, da er aus verschiedenen Quellen wie PDFs oder Webseiten stammen kann.\n",
301
+ "\n",
302
+ "Mach dir keine Sorgen über Formatierungsprobleme oder irrelevante Informationen; dein Ziel ist es, die wichtigsten Punkte zu extrahieren, Definitionen und interessante Fakten zu identifizieren, die in einem Podcast besprochen werden könnten.\n",
303
+ "\n",
304
+ "Definiere alle verwendeten Begriffe sorgfältig für ein breites Publikum.\n",
305
+ "\"\"\",\n",
306
+ " \"text_instructions\": \"Lies zuerst den Eingabetext sorgfältig durch und identifiziere die Hauptthemen, Schlüsselpunkte und interessante Fakten oder Anekdoten. Überlege, wie du diese Informationen auf unterhaltsame und ansprechende Weise präsentieren könntest, sodass sie für eine hochwertige Präsentation geeignet sind.\",\n",
307
+ " \"scratch_pad\": \"\"\"Denke kreativ darüber nach, wie du die Hauptthemen und Schlüsselpunkte, die du im Eingabetext identifiziert hast, diskutieren könntest. Verwende Analogien, Beispiele, Erzähltechniken oder hypothetische Szenarien, um den Inhalt für die Zuhörer nachvollziehbarer und ansprechender zu gestalten.\n",
308
+ "\n",
309
+ "Behalte im Hinterkopf, dass dein Podcast einem breiten Publikum zugänglich sein sollte, daher vermeide zu viel Fachjargon oder die Annahme von Vorwissen über das Thema. Falls nötig, überlege dir Möglichkeiten, um komplexe Konzepte kurz und einfach zu erklären.\n",
310
+ "\n",
311
+ "Nutze deine Fantasie, um Lücken im Eingabetext zu füllen oder um nachdenklich stimmende Fragen zu formulieren, die im Podcast erforscht werden könnten. Das Ziel ist es, einen informativen und unterhaltsamen Dialog zu schaffen, daher kannst du bei deinem Ansatz kreativ sein.\n",
312
+ "\n",
313
+ "Definiere alle verwendeten Begriffe klar und nimm dir die Zeit, den Hintergrund zu erläutern.\n",
314
+ "\n",
315
+ "Schreibe deine Brainstorming-Ideen und eine grobe Gliederung für den Podcast-Dialog hier auf. Achte darauf, die wichtigsten Erkenntnisse und Aussagen, die du am Ende wiederholen möchtest, zu notieren.\n",
316
+ "\n",
317
+ "Sorge dafür, dass es unterhaltsam und spannend ist.\n",
318
+ "\"\"\",\n",
319
+ " \"prelude\": \"\"\"Nun, da du Ideen gesammelt und eine grobe Gliederung erstellt hast, ist es an der Zeit, den eigentlichen Podcast-Dialog zu schreiben. Strebe einen natürlichen, konversationellen Fluss zwischen dem Moderator und etwaigen Gästen an. Nutze die besten Ideen aus deiner Brainstorming-Sitzung und erkläre alle komplexen Themen auf eine leicht verständliche Weise.\n",
320
+ "\"\"\",\n",
321
+ " \"dialog\": \"\"\"Schreibe hier einen sehr langen, fesselnden und informativen Podcast-Dialog, basierend auf den wichtigsten Punkten und kreativen Ideen, die du während der Brainstorming-Sitzung erarbeitet hast. Verwende einen konversationellen Ton und füge alle notwendigen Kontexte oder Erklärungen hinzu, um den Inhalt für ein allgemeines Publikum zugänglich zu machen.\n",
322
+ "\n",
323
+ "Verwende niemals erfundene Namen für die Moderatoren und Gäste, aber gestalte es zu einem fesselnden und immersiven Erlebnis für die Zuhörer. Verwende keine Platzhalter wie [Moderator] oder [Gast]. Dein Output wird direkt in Audio umgewandelt, daher entwerfe den Dialog so, dass er laut vorgelesen werden kann.\n",
324
+ "\n",
325
+ "Gestalte den Dialog so lang und detailliert wie möglich, bleibe dabei jedoch immer beim Thema und erhalte einen flüssigen, ansprechenden Verlauf. Verwende deine volle Output-Kapazität, um die längste mögliche Podcast-Episode zu erstellen, während du die wichtigsten Informationen aus dem Eingabetext auf unterhaltsame Weise vermittelst.\n",
326
+ "\n",
327
+ "Am Ende des Dialogs sollen der Moderator und die Gäste die wichtigsten Erkenntnisse und Aussagen ihres Gesprächs auf natürliche Weise zusammenfassen. Dies sollte organisch aus der Konversation hervorgehen und die wichtigsten Punkte in einem lockeren, gesprächigen Stil wiederholen. Vermeide es, wie eine offensichtliche Zusammenfassung zu klingen – das Ziel ist es, die zentralen Ideen ein letztes Mal zu verstärken, bevor der Podcast endet.\n",
328
+ "\n",
329
+ "Der Podcast sollte etwa 20.000 Wörter umfassen.\n",
330
+ "\"\"\",\n",
331
+ " },\n",
332
+ " \n",
333
+ "################# PODCAST SPANISH ##################\n",
334
+ "\"podcast (Spanish)\": {\n",
335
+ " \"intro\": \"\"\"Tu tarea es tomar el texto de entrada proporcionado y convertirlo en un diálogo de podcast animado, atractivo e informativo, al estilo de NPR. El texto de entrada puede estar desordenado o poco estructurado, ya que podría provenir de diversas fuentes como archivos PDF o páginas web.\n",
336
+ "\n",
337
+ "No te preocupes por los problemas de formato o por la información irrelevante; tu objetivo es extraer los puntos clave, identificar definiciones y hechos interesantes que podrían discutirse en un podcast.\n",
338
+ "\n",
339
+ "Define cuidadosamente todos los términos utilizados para una audiencia amplia.\n",
340
+ "\"\"\",\n",
341
+ " \"text_instructions\": \"Primero, lee detenidamente el texto de entrada e identifica los temas principales, los puntos clave y cualquier hecho o anécdota interesante. Piensa en cómo podrías presentar esta información de una manera divertida y atractiva, adecuada para una presentación de alta calidad.\",\n",
342
+ " \"scratch_pad\": \"\"\"Piensa de manera creativa sobre cómo discutir los temas principales y los puntos clave que has identificado en el texto de entrada. Considera usar analogías, ejemplos, técnicas narrativas o escenarios hipotéticos para hacer que el contenido sea más comprensible y atractivo para los oyentes.\n",
343
+ "\n",
344
+ "Ten en cuenta que tu podcast debe ser accesible para una audiencia general, así que evita usar demasiado jerga técnica o asumir que la audiencia tiene conocimientos previos del tema. Si es necesario, piensa en formas de explicar brevemente cualquier concepto complejo en términos sencillos.\n",
345
+ "\n",
346
+ "Usa tu imaginación para llenar los vacíos en el texto de entrada o para formular preguntas provocadoras que podrían explorarse en el podcast. El objetivo es crear un diálogo informativo y entretenido, por lo que puedes ser creativo en tu enfoque.\n",
347
+ "\n",
348
+ "Define claramente todos los términos utilizados y asegúrate de explicar el trasfondo.\n",
349
+ "\n",
350
+ "Escribe tus ideas de brainstorming y un esquema general del diálogo del podcast aquí. Asegúrate de anotar los puntos clave y las conclusiones que deseas reiterar al final.\n",
351
+ "\n",
352
+ "Asegúrate de que sea divertido y emocionante.\n",
353
+ "\"\"\",\n",
354
+ " \"prelude\": \"\"\"Ahora que has realizado una lluvia de ideas y has creado un esquema general, es hora de escribir el diálogo real del podcast. Apunta a un flujo natural y conversacional entre el presentador y cualquier invitado. Incorpora las mejores ideas de tu sesión de lluvia de ideas y asegúrate de explicar cualquier tema complejo de una manera fácil de entender.\n",
355
+ "\"\"\",\n",
356
+ " \"dialog\": \"\"\"Escribe aquí un diálogo de podcast muy largo, atractivo e informativo, basado en los puntos clave y las ideas creativas que se te ocurrieron durante la sesión de brainstorming. Usa un tono conversacional e incluye el contexto o las explicaciones necesarias para que el contenido sea accesible a una audiencia general.\n",
357
+ "\n",
358
+ "Nunca uses nombres inventados para los presentadores e invitados, pero haz que sea una experiencia atractiva e inmersiva para los oyentes. No incluyas ningún marcador de posición entre corchetes como [Presentador] o [Invitado]. Diseña tu salida para que sea leída en voz alta, ya que se convertirá directamente en audio.\n",
359
+ "\n",
360
+ "Haz el diálogo lo más largo y detallado posible, manteniéndote en el tema y asegurando un flujo atractivo. Apunta a utilizar toda tu capacidad de salida para crear el episodio de podcast más largo posible, mientras comunicas la información clave del texto de entrada de una manera entretenida.\n",
361
+ "\n",
362
+ "Al final del diálogo, el presentador y los invitados deben resumir naturalmente las principales ideas y conclusiones de su conversación. Esto debe fluir orgánicamente desde la conversación, reiterando los puntos clave de manera casual y conversacional. Evita que suene como un resumen obvio: el objetivo es reforzar las ideas centrales una última vez antes de finalizar.\n",
363
+ "\n",
364
+ "El podcast debe tener alrededor de 20,000 palabras.\n",
365
+ "\"\"\",\n",
366
+ " },\n",
367
+ "\n",
368
+ "################# PODCAST Portuguese ##################\n",
369
+ "\"podcast (Portuguese)\": {\n",
370
+ " \"intro\": \"\"\"Sua tarefa é pegar o texto de entrada fornecido e transformá-lo em um diálogo de podcast animado, envolvente e informativo, no estilo da NPR. O texto de entrada pode ser desorganizado ou não estruturado, pois pode vir de várias fontes, como PDFs ou páginas da web.\n",
371
+ "\n",
372
+ "Não se preocupe com problemas de formatação ou informações irrelevantes; seu objetivo é extrair os pontos principais, identificar definições e fatos interessantes que possam ser discutidos em um podcast.\n",
373
+ "\n",
374
+ "Defina cuidadosamente todos os termos usados para um público amplo.\n",
375
+ "\"\"\",\n",
376
+ " \"text_instructions\": \"Primeiro, leia atentamente o texto de entrada e identifique os principais tópicos, pontos-chave e quaisquer fatos ou anedotas interessantes. Pense em como você poderia apresentar essas informações de maneira divertida e envolvente, adequada para uma apresentação de alta qualidade.\",\n",
377
+ " \"scratch_pad\": \"\"\"Pense de maneira criativa sobre como discutir os principais tópicos e pontos-chave que você identificou no texto de entrada. Considere usar analogias, exemplos, técnicas de narrativa ou cenários hipotéticos para tornar o conteúdo mais acessível e interessante para os ouvintes.\n",
378
+ "\n",
379
+ "Tenha em mente que seu podcast deve ser acessível a um público geral, por isso, evite usar jargões técnicos ou presumir que o público tem conhecimento prévio do assunto. Se necessário, pense em maneiras de explicar brevemente qualquer conceito complexo em termos simples.\n",
380
+ "\n",
381
+ "Use sua imaginação para preencher quaisquer lacunas no texto de entrada ou para criar perguntas instigantes que possam ser exploradas no podcast. O objetivo é criar um diálogo informativo e divertido, então sinta-se à vontade para ser criativo em sua abordagem.\n",
382
+ "\n",
383
+ "Defina claramente todos os termos utilizados e faça um esforço para explicar o contexto.\n",
384
+ "\n",
385
+ "Escreva suas ideias de brainstorming e um esboço para o diálogo do podcast aqui. Certifique-se de anotar os principais insights e pontos que deseja reiterar no final.\n",
386
+ "\n",
387
+ "Certifique-se de que seja divertido e empolgante.\n",
388
+ "\"\"\",\n",
389
+ " \"prelude\": \"\"\"Agora que você já fez um brainstorming de ideias e criou um esboço, é hora de escrever o diálogo real do podcast. Busque um fluxo natural e conversacional entre o apresentador e qualquer convidado. Incorpore as melhores ideias de sua sessão de brainstorming e certifique-se de explicar qualquer tópico complexo de maneira fácil de entender.\n",
390
+ "\"\"\",\n",
391
+ " \"dialog\": \"\"\"Escreva aqui um diálogo de podcast muito longo, envolvente e informativo, com base nos pontos-chave e nas ideias criativas que você criou durante a sessão de brainstorming. Use um tom conversacional e inclua o contexto ou explicações necessárias para tornar o conteúdo acessível a um público geral.\n",
392
+ "\n",
393
+ "Nunca use nomes inventados para os apresentadores e convidados, mas faça com que seja uma experiência envolvente e imersiva para os ouvintes. Não inclua marcadores de posição como [Apresentador] ou [Convidado]. Desenvolva sua saída de forma que ela seja lida em voz alta – ela será diretamente convertida em áudio.\n",
394
+ "\n",
395
+ "Faça o diálogo o mais longo e detalhado possível, mantendo-se no tema e garantindo um fluxo envolvente. Use sua capacidade total de produção para criar o episódio de podcast mais longo possível, enquanto comunica as informações principais do texto de entrada de maneira divertida.\n",
396
+ "\n",
397
+ "No final do diálogo, o apresentador e os convidados devem resumir naturalmente as principais ideias e insights de sua conversa. Isso deve fluir organicamente a partir da conversa, reiterando os pontos-chave de maneira casual e conversacional. Evite soar como um resumo óbvio – o objetivo é reforçar as ideias centrais uma última vez antes de finalizar.\n",
398
+ "\n",
399
+ "O podcast deve ter cerca de 20.000 palavras.\n",
400
+ "\"\"\",\n",
401
+ " },\n",
402
+ "\n",
403
+ "################# PODCAST Hindi ##################\n",
404
+ "\"podcast (Hindi)\": {\n",
405
+ " \"intro\": \"\"\"आपका कार्य दिए गए इनपुट टेक्स्ट को लेकर उसे एक जीवंत, आकर्षक और जानकारीपूर्ण पॉडकास्ट वार्तालाप में बदलना है, NPR की शैली में। इनपुट टेक्स्ट असंगठित या अव्यवस्थित हो सकता है, क्योंकि यह विभिन्न स्रोतों जैसे PDFs या वेब पेजों से आ सकता है।\n",
406
+ "\n",
407
+ "फ़ॉर्मेटिंग समस्याओं या अप्रासंगिक जानकारी की चिंता न करें; आपका उद्देश्य मुख्य बिंदुओं को निकालना, परिभाषाओं और दिलचस्प तथ्यों को पहचानना है जिन्हें पॉडकास्ट में चर्चा की जा सकती है।\n",
408
+ "\n",
409
+ "सभी उपयोग किए गए शब्दों को सावधानीपूर्वक व्यापक दर्शकों के लिए परिभाषित करें।\n",
410
+ "\"\"\",\n",
411
+ " \"text_instructions\": \"सबसे पहले, इनपुट टेक्स्ट को ध्यान से पढ़ें और मुख्य विषयों, प्रमुख बिंदुओं और किसी भी दिलचस्प तथ्य या उपाख्यानों की पहचान करें। इस जानकारी को प्रस्तुत करने के बारे में सोचें कि आप इसे एक मज़ेदार, आकर्षक तरीके से कैसे प्रस्तुत कर सकते हैं जो उच्च गुणवत्ता वाली प्रस्तुति के लिए उपयुक्त हो।\",\n",
412
+ " \"scratch_pad\": \"\"\"मुख्य विषयों और प्रमुख बिंदुओं पर चर्चा करने के रचनात्मक तरीकों के बारे में सोचें जिन्हें आपने इनपुट टेक्स्ट में पहचाना है। उदाहरणों, कहानियों की तकनीकों, या काल्पनिक परिदृश्यों का उपयोग करके सामग्री को श्रोताओं के लिए अधिक सम्बंधित और आकर्षक बनाने पर विचार करें।\n",
413
+ "\n",
414
+ "ध्यान रखें कि आपका पॉडकास्ट एक सामान्य दर्शक के लिए सुलभ होना चाहिए, इसलिए बहुत अधिक तकनीकी शब्दजाल से बचें या यह न मानें कि विषय का पूर्व ज्ञान है। यदि आवश्यक हो, तो किसी भी जटिल अवधारणा को सरल शब्दों में संक्षेप में समझाने के तरीकों के बारे में सोचें।\n",
415
+ "\n",
416
+ "अपनी कल्पना का उपयोग करके इनपुट टेक्स्ट में किसी भी अंतराल को भरें या पॉडकास्ट में खोजे जा सकने वाले विचारोत्तेजक सवालों के साथ आएं। उद्देश्य एक जानकारीपूर्ण और मनोरंजक वार्तालाप बनाना है, इसलिए अपने दृष्टिकोण में रचनात्मक होने से न डरें।\n",
417
+ "\n",
418
+ "सभी उपयोग किए गए शब्दों को स्पष्ट रूप से परिभाषित करें और पृष्ठभूमि समझाने के लिए समय दें।\n",
419
+ "\n",
420
+ "यहां अपने विचार-मंथन और पॉडकास्ट वार्तालाप के लिए एक मोटा खाका लिखें। सुनिश्चित करें कि आपने उन प्रमुख अंतर्दृष्टियों और निष्कर्षों को नोट किया है जिन्हें आप अंत में दोहराना चाहते हैं।\n",
421
+ "\n",
422
+ "इसे मजेदार और रोमांचक बनाएं।\n",
423
+ "\"\"\",\n",
424
+ " \"prelude\": \"\"\"अब जब आपने विचार-मंथन किया है और एक मोटा खाका तैयार कर लिया है, तो वास्तविक पॉडकास्ट वार्तालाप लिखने का समय आ गया है। होस्ट और किसी भी अतिथि वक्ता के बीच एक स्वाभाविक, संवादात्मक प्रवाह की दिशा में कार्य करें। अपने विचार-मंथन सत्र से सर्वश्रेष्ठ विचारों को शामिल करें और सुनिश्चित करें कि किसी भी जटिल विषय को आसानी से समझ में आने वाले तरीके से समझाया जाए।\n",
425
+ "\"\"\",\n",
426
+ " \"dialog\": \"\"\"यहां एक बहुत लंबा, आकर्षक और जानकारीपूर्ण पॉडकास्ट वार्तालाप लिखें, जो उन प्रमुख बिंदुओं और रचनात्मक विचारों पर आधारित हो जो आपने विचार-मंथन सत्र के दौरान बनाए थे। एक संवादात्मक शैली का उपयोग करें और सामग्री को एक सामान्य दर्शक के लिए सुलभ बनाने के लिए किसी भी आवश्यक संदर्भ या व्याख्याएं शामिल करें।\n",
427
+ "\n",
428
+ "होस्ट और अतिथि वक्ताओं के लिए कभी भी काल्पनिक नामों का उपयोग न करें, बल्कि श्रोताओं के लिए इसे एक आकर्षक और immersive अनुभव बनाएं। किसी भी प्रकार के ब्रैकेटेड प्लेसहोल्डर्स जैसे [होस्ट] या [अतिथि] को शामिल न करें। अपनी आउटपुट को इस तरह डिज़ाइन करें कि इसे ज़ोर से पढ़ा जा सके – इसे सीधे ऑडियो में परिवर्तित किया जाएगा।\n",
429
+ "\n",
430
+ "डायलॉग को यथासंभव लंबा और विस्तृत बनाएं, फिर भी विषय पर बने रहें और प्रवाह को आकर्षक बनाए रखें। अपनी पूरी आउटपुट क्षमता का उपयोग करते हुए यथासंभव लंबे पॉडकास्ट एपिसोड को बनाएं, जबकि फिर भी इनपुट टेक्स्ट से प्रमुख जानकारी को मनोरंजक तरीके से संप्रेषित करें।\n",
431
+ "\n",
432
+ "वार्तालाप के अंत में, होस्ट और अतिथि वक्ता अपने चर्चा से स्वाभाविक रूप से मुख्य अंतर्दृष्टियों और निष्कर्षों को संक्षेप में प्रस्तुत करें। यह वार्तालाप से स्वाभाविक रूप से प्रवाहित होना चाहिए, अनौपचारिक, संवादात्मक तरीके से प्रमुख बिंदुओं को फिर से स्पष्ट करें। इसे स्पष्ट पुनरावृत्ति की तरह न बनाएं – उद्देश्य केंद्रीय विचारों को एक आखिरी बार सुदृढ़ करना है, इससे पहले कि वार्तालाप समाप्त हो जाए।\n",
433
+ "\n",
434
+ "पॉडकास्ट में लगभग 20,000 शब्द होने चाहिए।\n",
435
+ "\"\"\",\n",
436
+ " },\n",
437
+ "\n",
438
+ "################# PODCAST Chinese ##################\n",
439
+ "\"podcast (Chinese)\": {\n",
440
+ " \"intro\": \"\"\"你的任务是将提供的输入文本转变为一个生动、有趣、信息丰富的播客对话,风格类似NPR。输入文本可能是凌乱的或未结构化的,因为它可能来自PDF或网页等各种来源。\n",
441
+ "\n",
442
+ "不要担心格式问题或任何无关的信息;你的目标是提取关键点,识别定义和可能在播客中讨论的有趣事实。\n",
443
+ "\n",
444
+ "为广泛的听众仔细定义所有使用的术语。\n",
445
+ "\"\"\",\n",
446
+ " \"text_instructions\": \"首先,仔细阅读输入文本,识别主要话题、关键点和任何有趣的事实或轶事。思考如何以一种有趣且引人入胜的方式呈现这些信息,适合高质量的呈现。\",\n",
447
+ " \"scratch_pad\": \"\"\"集思广益,想出一些讨论你在输入文本中识别到的主要话题和关键点的创意方式。考虑使用类比、例子、讲故事的技巧或假设场景,让内容对听众更具相关性和吸引力。\n",
448
+ "\n",
449
+ "请记住,你的播客应面向普通大众,因此避免使用过多的行话或假设听众对该主题有预先的了解。如有必要,考虑简要解释任何复杂概念,用简单的术语进行说明。\n",
450
+ "\n",
451
+ "利用你的想象力填补输入文本中的任何空白,或提出一些值得探索的发人深省的问题。目标是创造一个信息丰富且有趣的对话,因此可以在方法上大胆创新。\n",
452
+ "\n",
453
+ "明确地定义所有使用的术语,并花时间解释背景。\n",
454
+ "\n",
455
+ "在这里写下你的头脑风暴想法和播客对话的粗略大纲。务必记录你想在结尾重复的关键见解和收获。\n",
456
+ "\n",
457
+ "确保让它有趣且令人兴奋。\n",
458
+ "\"\"\",\n",
459
+ " \"prelude\": \"\"\"现在你已经进行了头脑风暴并创建了一个粗略大纲,是时候编写实际的播客对话了。目标是主持人与嘉宾之间的自然对话流。结合你头脑风暴中的最佳想法,并确保以简单易懂的方式解释任何复杂的主题。\n",
460
+ "\"\"\",\n",
461
+ " \"dialog\": \"\"\"在这里写下一个非常长、引人入胜且信息丰富的播客对话,基于你在头脑风暴会议中提出的关键点和创意。使用对话语气,并包含任何必要的上下文或解释,使内容易于普通听众理解。\n",
462
+ "\n",
463
+ "不要为主持人和嘉宾使用虚构的名字,而是让听众体验一个引人入胜且沉浸式的经历。不要包括像[主持人]或[嘉宾]这样的占位符。设计你的输出以供大声朗读——它将被直接转换为音频。\n",
464
+ "\n",
465
+ "使对话尽可能长且详细,同时保持在主题上并维持引人入胜的流畅性。充分利用你的输出能力,创造尽可能长的播客节目,同时以有趣的方式传达输入文本中的关键信息。\n",
466
+ "\n",
467
+ "在对话的最后,主持人和嘉宾应自然总结他们讨论的主要见解和收获。这应从对话中自然流出,以随意、对话的方式重复关键点。避免显得像是显而易见的总结——目标是在结束前最后一次加强核心思想。\n",
468
+ "\n",
469
+ "播客应约有20,000字。\n",
470
+ "\"\"\",\n",
471
+ " },\n",
472
+ "\n",
473
+ "}\n",
474
+ "\n",
475
+ "# Function to update instruction fields based on template selection\n",
476
+ "def update_instructions(template):\n",
477
+ " return (\n",
478
+ " INSTRUCTION_TEMPLATES[template][\"intro\"],\n",
479
+ " INSTRUCTION_TEMPLATES[template][\"text_instructions\"],\n",
480
+ " INSTRUCTION_TEMPLATES[template][\"scratch_pad\"],\n",
481
+ " INSTRUCTION_TEMPLATES[template][\"prelude\"],\n",
482
+ " INSTRUCTION_TEMPLATES[template][\"dialog\"]\n",
483
+ " )\n",
484
+ "\n",
485
+ "import concurrent.futures as cf\n",
486
+ "import glob\n",
487
+ "import io\n",
488
+ "import os\n",
489
+ "import time\n",
490
+ "from pathlib import Path\n",
491
+ "from tempfile import NamedTemporaryFile\n",
492
+ "from typing import List, Literal\n",
493
+ "\n",
494
+ "import gradio as gr\n",
495
+ "\n",
496
+ "from loguru import logger\n",
497
+ "from openai import OpenAI\n",
498
+ "from promptic import llm\n",
499
+ "from pydantic import BaseModel, ValidationError\n",
500
+ "from pypdf import PdfReader\n",
501
+ "from tenacity import retry, retry_if_exception_type\n",
502
+ "\n",
503
+ "# Define standard values\n",
504
+ "STANDARD_TEXT_MODELS = [\n",
505
+ " \"o1-preview-2024-09-12\",\n",
506
+ " \"o1-preview\",\n",
507
+ " \"gpt-4o-2024-08-06\",\n",
508
+ " \"gpt-4o-mini\",\n",
509
+ " \"o1-mini-2024-09-12\",\n",
510
+ " \"o1-mini\",\n",
511
+ " \"chatgpt-4o-latest\",\n",
512
+ " \"gpt-4-turbo\",\n",
513
+ " \"openai/custom_model\",\n",
514
+ "]\n",
515
+ "\n",
516
+ "STANDARD_AUDIO_MODELS = [\n",
517
+ " \"tts-1\",\n",
518
+ " \"tts-1-hd\",\n",
519
+ "]\n",
520
+ "\n",
521
+ "STANDARD_VOICES = [\n",
522
+ " \"alloy\",\n",
523
+ " \"echo\",\n",
524
+ " \"fable\",\n",
525
+ " \"onyx\",\n",
526
+ " \"nova\",\n",
527
+ " \"shimmer\",\n",
528
+ "]\n",
529
+ "\n",
530
+ "class DialogueItem(BaseModel):\n",
531
+ " text: str\n",
532
+ " speaker: Literal[\"speaker-1\", \"speaker-2\"]\n",
533
+ "\n",
534
+ "class Dialogue(BaseModel):\n",
535
+ " scratchpad: str\n",
536
+ " dialogue: List[DialogueItem]\n",
537
+ "\n",
538
+ "def get_mp3(text: str, voice: str, audio_model: str, api_key: str = None) -> bytes:\n",
539
+ " client = OpenAI(\n",
540
+ " api_key=api_key or os.getenv(\"OPENAI_API_KEY\"),\n",
541
+ " )\n",
542
+ "\n",
543
+ " with client.audio.speech.with_streaming_response.create(\n",
544
+ " model=audio_model,\n",
545
+ " voice=voice,\n",
546
+ " input=text,\n",
547
+ " ) as response:\n",
548
+ " with io.BytesIO() as file:\n",
549
+ " for chunk in response.iter_bytes():\n",
550
+ " file.write(chunk)\n",
551
+ " return file.getvalue()\n",
552
+ "\n",
553
+ "\n",
554
+ "from functools import wraps\n",
555
+ "\n",
556
+ "def conditional_llm(model, api_base=None, api_key=None):\n",
557
+ " \"\"\"\n",
558
+ " Conditionally apply the @llm decorator based on the api_base parameter.\n",
559
+ " If api_base is provided, it applies the @llm decorator with api_base.\n",
560
+ " Otherwise, it applies the @llm decorator without api_base.\n",
561
+ " \"\"\"\n",
562
+ " def decorator(func):\n",
563
+ " if api_base:\n",
564
+ " return llm(model=model, api_base=api_base)(func)\n",
565
+ " else:\n",
566
+ " return llm(model=model, api_key=api_key)(func)\n",
567
+ " return decorator\n",
568
+ "\n",
569
+ "def generate_audio(\n",
570
+ " files: list,\n",
571
+ " openai_api_key: str = None,\n",
572
+ " text_model: str = \"o1-preview-2024-09-12\",\n",
573
+ " audio_model: str = \"tts-1\",\n",
574
+ " speaker_1_voice: str = \"alloy\",\n",
575
+ " speaker_2_voice: str = \"echo\",\n",
576
+ " api_base: str = None,\n",
577
+ " intro_instructions: str = '',\n",
578
+ " text_instructions: str = '',\n",
579
+ " scratch_pad_instructions: str = '',\n",
580
+ " prelude_dialog: str = '',\n",
581
+ " podcast_dialog_instructions: str = '',\n",
582
+ " edited_transcript: str = None,\n",
583
+ " user_feedback: str = None,\n",
584
+ " original_text: str = None,\n",
585
+ " debug = False,\n",
586
+ ") -> tuple:\n",
587
+ " # Validate API Key\n",
588
+ " if not os.getenv(\"OPENAI_API_KEY\") and not openai_api_key:\n",
589
+ " raise gr.Error(\"OpenAI API key is required\")\n",
590
+ "\n",
591
+ " combined_text = original_text or \"\"\n",
592
+ "\n",
593
+ " # If there's no original text, extract it from the uploaded files\n",
594
+ " if not combined_text:\n",
595
+ " for file in files:\n",
596
+ " with Path(file).open(\"rb\") as f:\n",
597
+ " reader = PdfReader(f)\n",
598
+ " text = \"\\n\\n\".join([page.extract_text() for page in reader.pages if page.extract_text()])\n",
599
+ " combined_text += text + \"\\n\\n\"\n",
600
+ "\n",
601
+ " # Configure the LLM based on selected model and api_base\n",
602
+ " @retry(retry=retry_if_exception_type(ValidationError))\n",
603
+ " @conditional_llm(model=text_model, api_base=api_base, api_key=openai_api_key)\n",
604
+ " def generate_dialogue(text: str, intro_instructions: str, text_instructions: str, scratch_pad_instructions: str, \n",
605
+ " prelude_dialog: str, podcast_dialog_instructions: str,\n",
606
+ " edited_transcript: str = None, user_feedback: str = None, ) -> Dialogue:\n",
607
+ " \"\"\"\n",
608
+ " {intro_instructions}\n",
609
+ " \n",
610
+ " Here is the original input text:\n",
611
+ " \n",
612
+ " <input_text>\n",
613
+ " {text}\n",
614
+ " </input_text>\n",
615
+ "\n",
616
+ " {text_instructions}\n",
617
+ " \n",
618
+ " <scratchpad>\n",
619
+ " {scratch_pad_instructions}\n",
620
+ " </scratchpad>\n",
621
+ " \n",
622
+ " {prelude_dialog}\n",
623
+ " \n",
624
+ " <podcast_dialogue>\n",
625
+ " {podcast_dialog_instructions}\n",
626
+ " </podcast_dialogue>\n",
627
+ " {edited_transcript}{user_feedback}\n",
628
+ " \"\"\"\n",
629
+ "\n",
630
+ " instruction_improve='Based on the original text, please generate an improved version of the dialogue by incorporating the edits, comments and feedback.'\n",
631
+ " edited_transcript_processed=\"\\nPreviously generated edited transcript, with specific edits and comments that I want you to carefully address:\\n\"+\"<edited_transcript>\\n\"+edited_transcript+\"</edited_transcript>\" if edited_transcript !=\"\" else \"\"\n",
632
+ " user_feedback_processed=\"\\nOverall user feedback:\\n\\n\"+user_feedback if user_feedback !=\"\" else \"\"\n",
633
+ "\n",
634
+ " if edited_transcript_processed.strip()!='' or user_feedback_processed.strip()!='':\n",
635
+ " user_feedback_processed=\"<requested_improvements>\"+user_feedback_processed+\"\\n\\n\"+instruction_improve+\"</requested_improvements>\" \n",
636
+ " \n",
637
+ " if debug:\n",
638
+ " logger.info (edited_transcript_processed)\n",
639
+ " logger.info (user_feedback_processed)\n",
640
+ " \n",
641
+ " # Generate the dialogue using the LLM\n",
642
+ " llm_output = generate_dialogue(\n",
643
+ " combined_text,\n",
644
+ " intro_instructions=intro_instructions,\n",
645
+ " text_instructions=text_instructions,\n",
646
+ " scratch_pad_instructions=scratch_pad_instructions,\n",
647
+ " prelude_dialog=prelude_dialog,\n",
648
+ " podcast_dialog_instructions=podcast_dialog_instructions,\n",
649
+ " edited_transcript=edited_transcript_processed,\n",
650
+ " user_feedback=user_feedback_processed\n",
651
+ " )\n",
652
+ "\n",
653
+ " # Generate audio from the transcript\n",
654
+ " audio = b\"\"\n",
655
+ " transcript = \"\"\n",
656
+ " characters = 0\n",
657
+ "\n",
658
+ " with cf.ThreadPoolExecutor() as executor:\n",
659
+ " futures = []\n",
660
+ " for line in llm_output.dialogue:\n",
661
+ " transcript_line = f\"{line.speaker}: {line.text}\"\n",
662
+ " voice = speaker_1_voice if line.speaker == \"speaker-1\" else speaker_2_voice\n",
663
+ " future = executor.submit(get_mp3, line.text, voice, audio_model, openai_api_key)\n",
664
+ " futures.append((future, transcript_line))\n",
665
+ " characters += len(line.text)\n",
666
+ "\n",
667
+ " for future, transcript_line in futures:\n",
668
+ " audio_chunk = future.result()\n",
669
+ " audio += audio_chunk\n",
670
+ " transcript += transcript_line + \"\\n\\n\"\n",
671
+ "\n",
672
+ " logger.info(f\"Generated {characters} characters of audio\")\n",
673
+ "\n",
674
+ " temporary_directory = \"./gradio_cached_examples/tmp/\"\n",
675
+ " os.makedirs(temporary_directory, exist_ok=True)\n",
676
+ "\n",
677
+ " # Use a temporary file -- Gradio's audio component doesn't work with raw bytes in Safari\n",
678
+ " temporary_file = NamedTemporaryFile(\n",
679
+ " dir=temporary_directory,\n",
680
+ " delete=False,\n",
681
+ " suffix=\".mp3\",\n",
682
+ " )\n",
683
+ " temporary_file.write(audio)\n",
684
+ " temporary_file.close()\n",
685
+ "\n",
686
+ " # Delete any files in the temp directory that end with .mp3 and are over a day old\n",
687
+ " for file in glob.glob(f\"{temporary_directory}*.mp3\"):\n",
688
+ " if os.path.isfile(file) and time.time() - os.path.getmtime(file) > 24 * 60 * 60:\n",
689
+ " os.remove(file)\n",
690
+ "\n",
691
+ " return temporary_file.name, transcript, combined_text\n",
692
+ "\n",
693
+ "def validate_and_generate_audio(*args):\n",
694
+ " files = args[0]\n",
695
+ " if not files:\n",
696
+ " return None, None, None, \"Please upload at least one PDF file before generating audio.\"\n",
697
+ " try:\n",
698
+ " audio_file, transcript, original_text = generate_audio(*args)\n",
699
+ " return audio_file, transcript, original_text, None # Return None as the error when successful\n",
700
+ " except Exception as e:\n",
701
+ " # If an error occurs during generation, return None for the outputs and the error message\n",
702
+ " return None, None, None, str(e)\n",
703
+ "\n",
704
+ "def edit_and_regenerate(edited_transcript, user_feedback, *args):\n",
705
+ " # Replace the original transcript and feedback in the args with the new ones\n",
706
+ " #new_args = list(args)\n",
707
+ " #new_args[-2] = edited_transcript # Update edited transcript\n",
708
+ " #new_args[-1] = user_feedback # Update user feedback\n",
709
+ " return validate_and_generate_audio(*new_args)\n",
710
+ "\n",
711
+ "# New function to handle user feedback and regeneration\n",
712
+ "def process_feedback_and_regenerate(feedback, *args):\n",
713
+ " # Add user feedback to the args\n",
714
+ " new_args = list(args)\n",
715
+ " new_args.append(feedback) # Add user feedback as a new argument\n",
716
+ " return validate_and_generate_audio(*new_args)\n",
717
+ "\n",
718
+ "with gr.Blocks(title=\"PDF to Audio\", css=\"\"\"\n",
719
+ " #header {\n",
720
+ " display: flex;\n",
721
+ " align-items: center;\n",
722
+ " justify-content: space-between;\n",
723
+ " padding: 20px;\n",
724
+ " background-color: transparent;\n",
725
+ " border-bottom: 1px solid #ddd;\n",
726
+ " }\n",
727
+ " #title {\n",
728
+ " font-size: 24px;\n",
729
+ " margin: 0;\n",
730
+ " }\n",
731
+ " #logo_container {\n",
732
+ " width: 200px;\n",
733
+ " height: 200px;\n",
734
+ " display: flex;\n",
735
+ " justify-content: center;\n",
736
+ " align-items: center;\n",
737
+ " }\n",
738
+ " #logo_image {\n",
739
+ " max-width: 100%;\n",
740
+ " max-height: 100%;\n",
741
+ " object-fit: contain;\n",
742
+ " }\n",
743
+ " #main_container {\n",
744
+ " margin-top: 20px;\n",
745
+ " }\n",
746
+ "\"\"\") as demo:\n",
747
+ " \n",
748
+ " with gr.Row(elem_id=\"header\"):\n",
749
+ " with gr.Column(scale=4):\n",
750
+ " gr.Markdown(\"# Convert PDFs into an audio podcast, lecture, summary and others\\n\\nFirst, upload one or more PDFs, select options, then push Generate Audio.\\n\\nYou can also select a variety of custom option and direct the way the result is generated.\", elem_id=\"title\")\n",
751
+ " with gr.Column(scale=1):\n",
752
+ " gr.HTML('''\n",
753
+ " <div id=\"logo_container\">\n",
754
+ " <img src=\"https://huggingface.co/spaces/lamm-mit/PDF2Audio/resolve/main/logo.png\" id=\"logo_image\" alt=\"Logo\">\n",
755
+ " </div>\n",
756
+ " ''')\n",
757
+ " #gr.Markdown(\"\") \n",
758
+ " submit_btn = gr.Button(\"Generate Audio\", elem_id=\"submit_btn\")\n",
759
+ "\n",
760
+ " with gr.Row(elem_id=\"main_container\"):\n",
761
+ " with gr.Column(scale=2):\n",
762
+ " files = gr.Files(label=\"PDFs\", file_types=[\"pdf\"], )\n",
763
+ " \n",
764
+ " openai_api_key = gr.Textbox(\n",
765
+ " label=\"OpenAI API Key\",\n",
766
+ " visible=True, # Always show the API key field\n",
767
+ " placeholder=\"Enter your OpenAI API Key here...\",\n",
768
+ " type=\"password\" # Hide the API key input\n",
769
+ " )\n",
770
+ " text_model = gr.Dropdown(\n",
771
+ " label=\"Text Generation Model\",\n",
772
+ " choices=STANDARD_TEXT_MODELS,\n",
773
+ " value=\"o1-preview-2024-09-12\", #\"gpt-4o-mini\",\n",
774
+ " info=\"Select the model to generate the dialogue text.\",\n",
775
+ " )\n",
776
+ " audio_model = gr.Dropdown(\n",
777
+ " label=\"Audio Generation Model\",\n",
778
+ " choices=STANDARD_AUDIO_MODELS,\n",
779
+ " value=\"tts-1\",\n",
780
+ " info=\"Select the model to generate the audio.\",\n",
781
+ " )\n",
782
+ " speaker_1_voice = gr.Dropdown(\n",
783
+ " label=\"Speaker 1 Voice\",\n",
784
+ " choices=STANDARD_VOICES,\n",
785
+ " value=\"alloy\",\n",
786
+ " info=\"Select the voice for Speaker 1.\",\n",
787
+ " )\n",
788
+ " speaker_2_voice = gr.Dropdown(\n",
789
+ " label=\"Speaker 2 Voice\",\n",
790
+ " choices=STANDARD_VOICES,\n",
791
+ " value=\"echo\",\n",
792
+ " info=\"Select the voice for Speaker 2.\",\n",
793
+ " )\n",
794
+ " api_base = gr.Textbox(\n",
795
+ " label=\"Custom API Base\",\n",
796
+ " placeholder=\"Enter custom API base URL if using a custom/local model...\",\n",
797
+ " info=\"If you are using a custom or local model, provide the API base URL here, e.g.: http://localhost:8080/v1 for llama.cpp REST server.\",\n",
798
+ " )\n",
799
+ "\n",
800
+ " with gr.Column(scale=3):\n",
801
+ " template_dropdown = gr.Dropdown(\n",
802
+ " label=\"Instruction Template\",\n",
803
+ " choices=list(INSTRUCTION_TEMPLATES.keys()),\n",
804
+ " value=\"podcast\",\n",
805
+ " info=\"Select the instruction template to use. You can also edit any of the fields for more tailored results.\",\n",
806
+ " )\n",
807
+ " intro_instructions = gr.Textbox(\n",
808
+ " label=\"Intro Instructions\",\n",
809
+ " lines=10,\n",
810
+ " value=INSTRUCTION_TEMPLATES[\"podcast\"][\"intro\"],\n",
811
+ " info=\"Provide the introductory instructions for generating the dialogue.\",\n",
812
+ " )\n",
813
+ " text_instructions = gr.Textbox(\n",
814
+ " label=\"Standard Text Analysis Instructions\",\n",
815
+ " lines=10,\n",
816
+ " placeholder=\"Enter text analysis instructions...\",\n",
817
+ " value=INSTRUCTION_TEMPLATES[\"podcast\"][\"text_instructions\"],\n",
818
+ " info=\"Provide the instructions for analyzing the raw data and text.\",\n",
819
+ " )\n",
820
+ " scratch_pad_instructions = gr.Textbox(\n",
821
+ " label=\"Scratch Pad Instructions\",\n",
822
+ " lines=15,\n",
823
+ " value=INSTRUCTION_TEMPLATES[\"podcast\"][\"scratch_pad\"],\n",
824
+ " info=\"Provide the scratch pad instructions for brainstorming presentation/dialogue content.\",\n",
825
+ " )\n",
826
+ " prelude_dialog = gr.Textbox(\n",
827
+ " label=\"Prelude Dialog\",\n",
828
+ " lines=5,\n",
829
+ " value=INSTRUCTION_TEMPLATES[\"podcast\"][\"prelude\"],\n",
830
+ " info=\"Provide the prelude instructions before the presentation/dialogue is developed.\",\n",
831
+ " )\n",
832
+ " podcast_dialog_instructions = gr.Textbox(\n",
833
+ " label=\"Podcast Dialog Instructions\",\n",
834
+ " lines=20,\n",
835
+ " value=INSTRUCTION_TEMPLATES[\"podcast\"][\"dialog\"],\n",
836
+ " info=\"Provide the instructions for generating the presentation or podcast dialogue.\",\n",
837
+ " )\n",
838
+ "\n",
839
+ " audio_output = gr.Audio(label=\"Audio\", format=\"mp3\", interactive=False, autoplay=False)\n",
840
+ " transcript_output = gr.Textbox(label=\"Transcript\", lines=20, show_copy_button=True)\n",
841
+ " original_text_output = gr.Textbox(label=\"Original Text\", lines=10, visible=False)\n",
842
+ " error_output = gr.Textbox(visible=False) # Hidden textbox to store error message\n",
843
+ "\n",
844
+ " use_edited_transcript = gr.Checkbox(label=\"Use Edited Transcript (check if you want to make edits to the initially generated transcript)\", value=False)\n",
845
+ " edited_transcript = gr.Textbox(label=\"Edit Transcript Here. E.g., mark edits in the text with clear instructions. E.g., '[ADD DEFINITION OF MATERIOMICS]'.\", lines=20, visible=False,\n",
846
+ " show_copy_button=True, interactive=False)\n",
847
+ "\n",
848
+ " user_feedback = gr.Textbox(label=\"Provide Feedback or Notes\", lines=10, #placeholder=\"Enter your feedback or notes here...\"\n",
849
+ " )\n",
850
+ " regenerate_btn = gr.Button(\"Regenerate Audio with Edits and Feedback\")\n",
851
+ " # Function to update the interactive state of edited_transcript\n",
852
+ " def update_edit_box(checkbox_value):\n",
853
+ " return gr.update(interactive=checkbox_value, lines=20 if checkbox_value else 20, visible=True if checkbox_value else False)\n",
854
+ "\n",
855
+ " # Update the interactive state of edited_transcript when the checkbox is toggled\n",
856
+ " use_edited_transcript.change(\n",
857
+ " fn=update_edit_box,\n",
858
+ " inputs=[use_edited_transcript],\n",
859
+ " outputs=[edited_transcript]\n",
860
+ " )\n",
861
+ " # Update instruction fields when template is changed\n",
862
+ " template_dropdown.change(\n",
863
+ " fn=update_instructions,\n",
864
+ " inputs=[template_dropdown],\n",
865
+ " outputs=[intro_instructions, text_instructions, scratch_pad_instructions, prelude_dialog, podcast_dialog_instructions]\n",
866
+ " )\n",
867
+ " \n",
868
+ " submit_btn.click(\n",
869
+ " fn=validate_and_generate_audio,\n",
870
+ " inputs=[\n",
871
+ " files, openai_api_key, text_model, audio_model, \n",
872
+ " speaker_1_voice, speaker_2_voice, api_base,\n",
873
+ " intro_instructions, text_instructions, scratch_pad_instructions, \n",
874
+ " prelude_dialog, podcast_dialog_instructions, \n",
875
+ " edited_transcript, # placeholder for edited_transcript\n",
876
+ " user_feedback, # placeholder for user_feedback\n",
877
+ " ],\n",
878
+ " outputs=[audio_output, transcript_output, original_text_output, error_output]\n",
879
+ " ).then(\n",
880
+ " fn=lambda audio, transcript, original_text, error: (\n",
881
+ " transcript if transcript else \"\",\n",
882
+ " error if error else None\n",
883
+ " ),\n",
884
+ " inputs=[audio_output, transcript_output, original_text_output, error_output],\n",
885
+ " outputs=[edited_transcript, error_output]\n",
886
+ " ).then(\n",
887
+ " fn=lambda error: gr.Warning(error) if error else None,\n",
888
+ " inputs=[error_output],\n",
889
+ " outputs=[]\n",
890
+ " )\n",
891
+ "\n",
892
+ " regenerate_btn.click(\n",
893
+ " fn=lambda use_edit, edit, *args: validate_and_generate_audio(\n",
894
+ " *args[:12], # All inputs up to podcast_dialog_instructions\n",
895
+ " edit if use_edit else \"\", # Use edited transcript if checkbox is checked, otherwise empty string\n",
896
+ " *args[12:] # user_feedback and original_text_output\n",
897
+ " ),\n",
898
+ " inputs=[\n",
899
+ " use_edited_transcript, edited_transcript,\n",
900
+ " files, openai_api_key, text_model, audio_model, \n",
901
+ " speaker_1_voice, speaker_2_voice, api_base,\n",
902
+ " intro_instructions, text_instructions, scratch_pad_instructions, \n",
903
+ " prelude_dialog, podcast_dialog_instructions,\n",
904
+ " user_feedback, original_text_output\n",
905
+ " ],\n",
906
+ " outputs=[audio_output, transcript_output, original_text_output, error_output]\n",
907
+ " ).then(\n",
908
+ " fn=lambda audio, transcript, original_text, error: (\n",
909
+ " transcript if transcript else \"\",\n",
910
+ " error if error else None\n",
911
+ " ),\n",
912
+ " inputs=[audio_output, transcript_output, original_text_output, error_output],\n",
913
+ " outputs=[edited_transcript, error_output]\n",
914
+ " ).then(\n",
915
+ " fn=lambda error: gr.Warning(error) if error else None,\n",
916
+ " inputs=[error_output],\n",
917
+ " outputs=[]\n",
918
+ " )\n",
919
+ "\n",
920
+ " # Add README content at the bottom\n",
921
+ " gr.Markdown(\"---\") # Horizontal line to separate the interface from README\n",
922
+ " gr.Markdown(read_readme())\n",
923
+ " \n",
924
+ "# Enable queueing for better performance\n",
925
+ "demo.queue(max_size=20, default_concurrency_limit=32)\n",
926
+ "\n",
927
+ "# Launch the Gradio app\n",
928
+ "if __name__ == \"__main__\":\n",
929
+ " demo.launch()"
930
+ ]
931
+ },
932
+ {
933
+ "cell_type": "markdown",
934
+ "metadata": {
935
+ "id": "Fvlp5EvQ2ApM"
936
+ },
937
+ "source": [
938
+ "## Credits\n",
939
+ "\n",
940
+ "This project was inspired by and based on the code available at [https://github.com/knowsuchagency/pdf-to-podcast](https://github.com/knowsuchagency/pdf-to-podcast) and [https://github.com/knowsuchagency/promptic](https://github.com/knowsuchagency/promptic).\n",
941
+ "\n",
942
+ "```bibtex\n",
943
+ "@article{ghafarollahi2024sciagentsautomatingscientificdiscovery,\n",
944
+ " title={SciAgents: Automating scientific discovery through multi-agent intelligent graph reasoning},\n",
945
+ " author={Alireza Ghafarollahi and Markus J. Buehler},\n",
946
+ " year={2024},\n",
947
+ " eprint={2409.05556},\n",
948
+ " archivePrefix={arXiv},\n",
949
+ " primaryClass={cs.AI},\n",
950
+ " url={https://arxiv.org/abs/2409.05556},\n",
951
+ "}\n",
952
+ "@article{buehler2024graphreasoning,\n",
953
+ " title={Accelerating Scientific Discovery with Generative Knowledge Extraction, Graph-Based Representation, and Multimodal Intelligent Graph Reasoning},\n",
954
+ " author={Markus J. Buehler},\n",
955
+ " journal={Machine Learning: Science and Technology},\n",
956
+ " year={2024},\n",
957
+ " url={http://iopscience.iop.org/article/10.1088/2632-2153/ad7228},\n",
958
+ "}\n",
959
+ "```"
960
+ ]
961
+ }
962
+ ],
963
+ "metadata": {
964
+ "colab": {
965
+ "provenance": []
966
+ },
967
+ "kernelspec": {
968
+ "display_name": "Python 3",
969
+ "name": "python3"
970
+ },
971
+ "language_info": {
972
+ "name": "python"
973
+ }
974
+ },
975
+ "nbformat": 4,
976
+ "nbformat_minor": 0
977
+ }
README.md CHANGED
@@ -1,12 +1,127 @@
1
  ---
2
  title: PDF2Audio
3
- emoji:
4
- colorFrom: gray
5
- colorTo: indigo
6
  sdk: gradio
7
  sdk_version: 4.44.0
8
- app_file: app.py
9
- pinned: false
10
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
  title: PDF2Audio
3
+ app_file: app.py
 
 
4
  sdk: gradio
5
  sdk_version: 4.44.0
 
 
6
  ---
7
+ # PDF to Audio Converter
8
+
9
+ This code can be used to convert PDFs into audio podcasts, lectures, summaries, and more. It uses OpenAI's GPT models for text generation and text-to-speech conversion. You can also edit a draft transcript (multiple times) and provide specific comments, or overall directives on how it could be adapted or improved.
10
+
11
+ ![image](https://github.com/user-attachments/assets/ef8a5e84-d532-4e0e-b08b-fb7be2f98469)
12
+
13
+ ## Features
14
+
15
+ - Upload multiple PDF files
16
+ - Choose from different instruction templates (podcast, lecture, summary, etc.)
17
+ - Customize text generation and audio models
18
+ - Select different voices for speakers
19
+ - Iterate on the draft via specific or general commments, and/or edits to the transcript and specific feedback to the model for improvements
20
+
21
+ ## Use in Colab
22
+
23
+ [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/lamm-mit/PDF2Audio/blob/main/PDF2Audio.ipynb)
24
+
25
+ ## Local Installation
26
+
27
+ Follow these steps to set up PDF2Audio on your local machine using Conda:
28
+
29
+ 1. Clone the repository:
30
+ ```
31
+ git clone https://github.com/lamm-mit/PDF2Audio.git
32
+ cd PDF2Audio
33
+ ```
34
+
35
+ 2. Install Miniconda (if you haven't already):
36
+ - Download the installer from [Miniconda website](https://docs.conda.io/en/latest/miniconda.html)
37
+ - Follow the installation instructions for your operating system
38
+ - Verify the installation:
39
+ ```
40
+ conda --version
41
+ ```
42
+
43
+ 3. Create a new Conda environment:
44
+ ```
45
+ conda create -n pdf2audio python=3.9
46
+ ```
47
+
48
+ 4. Activate the Conda environment:
49
+ ```
50
+ conda activate pdf2audio
51
+ ```
52
+
53
+ 5. Install the required dependencies:
54
+ ```
55
+ pip install -r requirements.txt
56
+ ```
57
+
58
+ 6. Set up your OpenAI API key:
59
+ Create a `.env` file in the project root directory and add your OpenAI API key:
60
+ ```
61
+ OPENAI_API_KEY=your_api_key_here
62
+ ```
63
+
64
+ ## Running the App
65
+
66
+ To run the PDF2Audio app:
67
+
68
+ 1. Ensure you're in the project directory and your Conda environment is activated:
69
+ ```
70
+ conda activate pdf2audio
71
+ ```
72
+
73
+ 2. Run the Python script that launches the Gradio interface:
74
+ ```
75
+ python app.py
76
+ ```
77
+
78
+ 3. Open your web browser and go to the URL provided in the terminal (typically `http://127.0.0.1:7860`).
79
+
80
+ 4. Use the Gradio interface to upload a PDF file and convert it to audio.
81
+
82
+ ## How to Use
83
+
84
+ 1. Upload one or more PDF files
85
+ 2. Select the desired instruction template
86
+ 3. Customize the instructions if needed
87
+ 4. Click "Generate Audio" to create your audio content
88
+
89
+ ## Access via 🤗 Hugging Face Spaces
90
+
91
+ [lamm-mit/PDF2Audio](https://huggingface.co/spaces/lamm-mit/PDF2Audio)
92
+
93
+
94
+ ## Example result
95
+
96
+ <audio controls>
97
+ <source src="[https://user-images.githubusercontent.com/your-username/your-repo/path-to-audio-file.mp3](https://raw.githubusercontent.com/lamm-mit/PDF2Audio/main/SciAgents%20discovery%20summary%20-%20example.mp3)" type="audio/mpeg">
98
+ Your browser does not support the audio element.
99
+ </audio>
100
+
101
+ ## Note
102
+
103
+ This app requires an OpenAI API key to function.
104
+
105
+ ## Credits
106
+
107
+ This project was inspired by and based on the code available at [https://github.com/knowsuchagency/pdf-to-podcast](https://github.com/knowsuchagency/pdf-to-podcast) and [https://github.com/knowsuchagency/promptic](https://github.com/knowsuchagency/promptic).
108
+
109
+ ```bibtex
110
+ @article{ghafarollahi2024sciagentsautomatingscientificdiscovery,
111
+ title={SciAgents: Automating scientific discovery through multi-agent intelligent graph reasoning},
112
+ author={Alireza Ghafarollahi and Markus J. Buehler},
113
+ year={2024},
114
+ eprint={2409.05556},
115
+ archivePrefix={arXiv},
116
+ primaryClass={cs.AI},
117
+ url={https://arxiv.org/abs/2409.05556},
118
+ }
119
+ @article{buehler2024graphreasoning,
120
+ title={Accelerating Scientific Discovery with Generative Knowledge Extraction, Graph-Based Representation, and Multimodal Intelligent Graph Reasoning},
121
+ author={Markus J. Buehler},
122
+ journal={Machine Learning: Science and Technology},
123
+ year={2024},
124
+ url={http://iopscience.iop.org/article/10.1088/2632-2153/ad7228},
125
+ }
126
+ ```
127
 
 
app.py ADDED
@@ -0,0 +1,892 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import concurrent.futures as cf
2
+ import glob
3
+ import io
4
+ import os
5
+ import time
6
+ from pathlib import Path
7
+ from tempfile import NamedTemporaryFile
8
+ from typing import List, Literal
9
+
10
+ import gradio as gr
11
+
12
+ from loguru import logger
13
+ from openai import OpenAI
14
+ from promptic import llm
15
+ from pydantic import BaseModel, ValidationError
16
+ from pypdf import PdfReader
17
+ from tenacity import retry, retry_if_exception_type
18
+
19
+ import re
20
+ from dotenv import load_dotenv
21
+ load_dotenv()
22
+ # 现在你可以使用 os.getenv() 来获取环境变量
23
+ openai_api_key = os.getenv("OPENAI_API_KEY")
24
+
25
+
26
+
27
+ def read_readme():
28
+ readme_path = Path("README.md")
29
+ if readme_path.exists():
30
+ with open(readme_path, "r") as file:
31
+ content = file.read()
32
+ # Use regex to remove metadata enclosed in -- ... --
33
+ content = re.sub(r'--.*?--', '', content, flags=re.DOTALL)
34
+ return content
35
+ else:
36
+ return "README.md not found. Please check the repository for more information."
37
+
38
+ # Define multiple sets of instruction templates
39
+ INSTRUCTION_TEMPLATES = {
40
+ ################# PODCAST ##################
41
+ "podcast": {
42
+ "intro": """Your task is to take the input text provided and turn it into an lively, engaging, informative podcast dialogue, in the style of NPR. The input text may be messy or unstructured, as it could come from a variety of sources like PDFs or web pages.
43
+
44
+ Don't worry about the formatting issues or any irrelevant information; your goal is to extract the key points, identify definitions, and interesting facts that could be discussed in a podcast.
45
+
46
+ Define all terms used carefully for a broad audience of listeners.
47
+ """,
48
+ "text_instructions": "First, carefully read through the input text and identify the main topics, key points, and any interesting facts or anecdotes. Think about how you could present this information in a fun, engaging way that would be suitable for a high quality presentation.",
49
+ "scratch_pad": """Brainstorm creative ways to discuss the main topics and key points you identified in the input text. Consider using analogies, examples, storytelling techniques, or hypothetical scenarios to make the content more relatable and engaging for listeners.
50
+
51
+ Keep in mind that your podcast should be accessible to a general audience, so avoid using too much jargon or assuming prior knowledge of the topic. If necessary, think of ways to briefly explain any complex concepts in simple terms.
52
+
53
+ Use your imagination to fill in any gaps in the input text or to come up with thought-provoking questions that could be explored in the podcast. The goal is to create an informative and entertaining dialogue, so feel free to be creative in your approach.
54
+
55
+ Define all terms used clearly and spend effort to explain the background.
56
+
57
+ Write your brainstorming ideas and a rough outline for the podcast dialogue here. Be sure to note the key insights and takeaways you want to reiterate at the end.
58
+
59
+ Make sure to make it fun and exciting.
60
+ """,
61
+ "prelude": """Now that you have brainstormed ideas and created a rough outline, it's time to write the actual podcast dialogue. Aim for a natural, conversational flow between the host and any guest speakers. Incorporate the best ideas from your brainstorming session and make sure to explain any complex topics in an easy-to-understand way.
62
+ """,
63
+ "dialog": """Write a very long, engaging, informative podcast dialogue here, based on the key points and creative ideas you came up with during the brainstorming session. Use a conversational tone and include any necessary context or explanations to make the content accessible to a general audience.
64
+
65
+ Never use made-up names for the hosts and guests, but make it an engaging and immersive experience for listeners. Do not include any bracketed placeholders like [Host] or [Guest]. Design your output to be read aloud -- it will be directly converted into audio.
66
+
67
+ Make the dialogue as long and detailed as possible, while still staying on topic and maintaining an engaging flow. Aim to use your full output capacity to create the longest podcast episode you can, while still communicating the key information from the input text in an entertaining way.
68
+
69
+ At the end of the dialogue, have the host and guest speakers naturally summarize the main insights and takeaways from their discussion. This should flow organically from the conversation, reiterating the key points in a casual, conversational manner. Avoid making it sound like an obvious recap - the goal is to reinforce the central ideas one last time before signing off.
70
+
71
+ The podcast should have around 20000 words. 輸出文字為繁體中文,請注意。
72
+ """,
73
+ },
74
+ ################# MATERIAL DISCOVERY SUMMARY ##################
75
+ "SciAgents material discovery summary": {
76
+ "intro": """Your task is to take the input text provided and turn it into a lively, engaging conversation between a professor and a student in a panel discussion that describes a new material. The professor acts like Richard Feynman, but you never mention the name.
77
+
78
+ The input text is the result of a design developed by SciAgents, an AI tool for scientific discovery that has come up with a detailed materials design.
79
+
80
+ Don't worry about the formatting issues or any irrelevant information; your goal is to extract the key points, identify definitions, and interesting facts that could be discussed in a podcast.
81
+
82
+ Define all terms used carefully for a broad audience of listeners.
83
+ """,
84
+ "text_instructions": "First, carefully read through the input text and identify the main topics, key points, and any interesting facts or anecdotes. Think about how you could present this information in a fun, engaging way that would be suitable for a high quality presentation.",
85
+ "scratch_pad": """Brainstorm creative ways to discuss the main topics and key points you identified in the material design summary, especially paying attention to design features developed by SciAgents. Consider using analogies, examples, storytelling techniques, or hypothetical scenarios to make the content more relatable and engaging for listeners.
86
+
87
+ Keep in mind that your description should be accessible to a general audience, so avoid using too much jargon or assuming prior knowledge of the topic. If necessary, think of ways to briefly explain any complex concepts in simple terms.
88
+
89
+ Use your imagination to fill in any gaps in the input text or to come up with thought-provoking questions that could be explored in the podcast. The goal is to create an informative and entertaining dialogue, so feel free to be creative in your approach.
90
+
91
+ Define all terms used clearly and spend effort to explain the background.
92
+
93
+ Write your brainstorming ideas and a rough outline for the podcast dialogue here. Be sure to note the key insights and takeaways you want to reiterate at the end.
94
+
95
+ Make sure to make it fun and exciting. You never refer to the podcast, you just discuss the discovery and you focus on the new material design only.
96
+ """,
97
+ "prelude": """Now that you have brainstormed ideas and created a rough outline, it's time to write the actual podcast dialogue. Aim for a natural, conversational flow between the host and any guest speakers. Incorporate the best ideas from your brainstorming session and make sure to explain any complex topics in an easy-to-understand way.
98
+ """,
99
+ "dialog": """Write a very long, engaging, informative dialogue here, based on the key points and creative ideas you came up with during the brainstorming session. The presentation must focus on the novel aspects of the material design, behavior, and all related aspects.
100
+
101
+ Use a conversational tone and include any necessary context or explanations to make the content accessible to a general audience, but make it detailed, logical, and technical so that it has all necessary aspects for listeners to understand the material and its unexpected properties.
102
+
103
+ Remember, this describes a design developed by SciAgents, and this must be explicitly stated for the listeners.
104
+
105
+ Never use made-up names for the hosts and guests, but make it an engaging and immersive experience for listeners. Do not include any bracketed placeholders like [Host] or [Guest]. Design your output to be read aloud -- it will be directly converted into audio.
106
+
107
+ Make the dialogue as long and detailed as possible with great scientific depth, while still staying on topic and maintaining an engaging flow. Aim to use your full output capacity to create the longest podcast episode you can, while still communicating the key information from the input text in an entertaining way.
108
+
109
+ At the end of the dialogue, have the host and guest speakers naturally summarize the main insights and takeaways from their discussion. This should flow organically from the conversation, reiterating the key points in a casual, conversational manner. Avoid making it sound like an obvious recap - the goal is to reinforce the central ideas one last time before signing off.
110
+
111
+ The conversation should have around 20000 words. 請用**繁體中文**輸出文稿
112
+ """
113
+ },
114
+ ################# LECTURE ##################
115
+ "lecture": {
116
+ "intro": """You are Professor Richard Feynman. Your task is to develop a script for a lecture. You never mention your name.
117
+
118
+ The material covered in the lecture is based on the provided text.
119
+
120
+ Don't worry about the formatting issues or any irrelevant information; your goal is to extract the key points, identify definitions, and interesting facts that need to be covered in the lecture.
121
+
122
+ Define all terms used carefully for a broad audience of students.
123
+ """,
124
+ "text_instructions": "First, carefully read through the input text and identify the main topics, key points, and any interesting facts or anecdotes. Think about how you could present this information in a fun, engaging way that would be suitable for a high quality presentation.",
125
+ "scratch_pad": """
126
+ Brainstorm creative ways to discuss the main topics and key points you identified in the input text. Consider using analogies, examples, storytelling techniques, or hypothetical scenarios to make the content more relatable and engaging for listeners.
127
+
128
+ Keep in mind that your lecture should be accessible to a general audience, so avoid using too much jargon or assuming prior knowledge of the topic. If necessary, think of ways to briefly explain any complex concepts in simple terms.
129
+
130
+ Use your imagination to fill in any gaps in the input text or to come up with thought-provoking questions that could be explored in the podcast. The goal is to create an informative and entertaining dialogue, so feel free to be creative in your approach.
131
+
132
+ Define all terms used clearly and spend effort to explain the background.
133
+
134
+ Write your brainstorming ideas and a rough outline for the lecture here. Be sure to note the key insights and takeaways you want to reiterate at the end.
135
+
136
+ Make sure to make it fun and exciting.
137
+ """,
138
+ "prelude": """Now that you have brainstormed ideas and created a rough outline, it's time to write the actual podcast dialogue. Aim for a natural, conversational flow between the host and any guest speakers. Incorporate the best ideas from your brainstorming session and make sure to explain any complex topics in an easy-to-understand way.
139
+ """,
140
+ "dialog": """Write a very long, engaging, informative script here, based on the key points and creative ideas you came up with during the brainstorming session. Use a conversational tone and include any necessary context or explanations to make the content accessible to the students.
141
+
142
+ Include clear definitions and terms, and examples.
143
+
144
+ Do not include any bracketed placeholders like [Host] or [Guest]. Design your output to be read aloud -- it will be directly converted into audio.
145
+
146
+ There is only one speaker, you, the professor. Stay on topic and maintaining an engaging flow. Aim to use your full output capacity to create the longest lecture you can, while still communicating the key information from the input text in an engaging way.
147
+
148
+ At the end of the lecture, naturally summarize the main insights and takeaways from the lecture. This should flow organically from the conversation, reiterating the key points in a casual, conversational manner.
149
+
150
+ Avoid making it sound like an obvious recap - the goal is to reinforce the central ideas covered in this lecture one last time before class is over.
151
+
152
+ The lecture should have around 20000 words.
153
+ """,
154
+ },
155
+ ################# SUMMARY ##################
156
+ "summary": {
157
+ "intro": """Your task is to develop a summary of a paper. You never mention your name.
158
+
159
+ Don't worry about the formatting issues or any irrelevant information; your goal is to extract the key points, identify definitions, and interesting facts that need to be summarized.
160
+
161
+ Define all terms used carefully for a broad audience.
162
+ """,
163
+ "text_instructions": "First, carefully read through the input text and identify the main topics, key points, and key facts. Think about how you could present this information in an accurate summary.",
164
+ "scratch_pad": """Brainstorm creative ways to present the main topics and key points you identified in the input text. Consider using analogies, examples, or hypothetical scenarios to make the content more relatable and engaging for listeners.
165
+
166
+ Keep in mind that your summary should be accessible to a general audience, so avoid using too much jargon or assuming prior knowledge of the topic. If necessary, think of ways to briefly explain any complex concepts in simple terms. Define all terms used clearly and spend effort to explain the background.
167
+
168
+ Write your brainstorming ideas and a rough outline for the summary here. Be sure to note the key insights and takeaways you want to reiterate at the end.
169
+
170
+ Make sure to make it engaging and exciting.
171
+ """,
172
+ "prelude": """Now that you have brainstormed ideas and created a rough outline, it is time to write the actual summary. Aim for a natural, conversational flow between the host and any guest speakers. Incorporate the best ideas from your brainstorming session and make sure to explain any complex topics in an easy-to-understand way.
173
+ """,
174
+ "dialog": """Write a a script here, based on the key points and creative ideas you came up with during the brainstorming session. Use a conversational tone and include any necessary context or explanations to make the content accessible to the the audience.
175
+
176
+ Start your script by stating that this is a summary, referencing the title or headings in the input text. If the input text has no title, come up with a succinct summary of what is covered to open.
177
+
178
+ Include clear definitions and terms, and examples, of all key issues.
179
+
180
+ Do not include any bracketed placeholders like [Host] or [Guest]. Design your output to be read aloud -- it will be directly converted into audio.
181
+
182
+ There is only one speaker, you. Stay on topic and maintaining an engaging flow.
183
+
184
+ Naturally summarize the main insights and takeaways from the summary. This should flow organically from the conversation, reiterating the key points in a casual, conversational manner.
185
+
186
+ The summary should have around 1024 words.
187
+ """,
188
+ },
189
+ ################# SHORT SUMMARY ##################
190
+ "short summary": {
191
+ "intro": """Your task is to develop a summary of a paper. You never mention your name.
192
+
193
+ Don't worry about the formatting issues or any irrelevant information; your goal is to extract the key points, identify definitions, and interesting facts that need to be summarized.
194
+
195
+ Define all terms used carefully for a broad audience.
196
+ """,
197
+ "text_instructions": "First, carefully read through the input text and identify the main topics, key points, and key facts. Think about how you could present this information in an accurate summary.",
198
+ "scratch_pad": """Brainstorm creative ways to present the main topics and key points you identified in the input text. Consider using analogies, examples, or hypothetical scenarios to make the content more relatable and engaging for listeners.
199
+
200
+ Keep in mind that your summary should be accessible to a general audience, so avoid using too much jargon or assuming prior knowledge of the topic. If necessary, think of ways to briefly explain any complex concepts in simple terms. Define all terms used clearly and spend effort to explain the background.
201
+
202
+ Write your brainstorming ideas and a rough outline for the summary here. Be sure to note the key insights and takeaways you want to reiterate at the end.
203
+
204
+ Make sure to make it engaging and exciting.
205
+ """,
206
+ "prelude": """Now that you have brainstormed ideas and created a rough outline, it is time to write the actual summary. Aim for a natural, conversational flow between the host and any guest speakers. Incorporate the best ideas from your brainstorming session and make sure to explain any complex topics in an easy-to-understand way.
207
+ """,
208
+ "dialog": """Write a a script here, based on the key points and creative ideas you came up with during the brainstorming session. Keep it concise, and use a conversational tone and include any necessary context or explanations to make the content accessible to the the audience.
209
+
210
+ Start your script by stating that this is a summary, referencing the title or headings in the input text. If the input text has no title, come up with a succinct summary of what is covered to open.
211
+
212
+ Include clear definitions and terms, and examples, of all key issues.
213
+
214
+ Do not include any bracketed placeholders like [Host] or [Guest]. Design your output to be read aloud -- it will be directly converted into audio.
215
+
216
+ There is only one speaker, you. Stay on topic and maintaining an engaging flow.
217
+
218
+ Naturally summarize the main insights and takeaways from the short summary. This should flow organically from the conversation, reiterating the key points in a casual, conversational manner.
219
+
220
+ The summary should have around 256 words.
221
+ """,
222
+ },
223
+
224
+ ################# PODCAST French ##################
225
+ "podcast (French)": {
226
+ "intro": """Votre tâche consiste à prendre le texte fourni et à le transformer en un dialogue de podcast vivant, engageant et informatif, dans le style de NPR. Le texte d'entrée peut être désorganisé ou non structuré, car il peut provenir de diverses sources telles que des fichiers PDF ou des pages web.
227
+
228
+ Ne vous inquiétez pas des problèmes de formatage ou des informations non pertinentes ; votre objectif est d'extraire les points clés, d'identifier les définitions et les faits intéressants qui pourraient être discutés dans un podcast.
229
+
230
+ Définissez soigneusement tous les termes utilisés pour un public large.
231
+ """,
232
+ "text_instructions": "Tout d'abord, lisez attentivement le texte d'entrée et identifiez les principaux sujets, points clés et faits ou anecdotes intéressants. Réfléchissez à la manière dont vous pourriez présenter ces informations de manière amusante et engageante, convenant à une présentation de haute qualité.",
233
+ "scratch_pad": """Réfléchissez à des moyens créatifs pour discuter des principaux sujets et points clés que vous avez identifiés dans le texte d'entrée. Envisagez d'utiliser des analogies, des exemples, des techniques de narration ou des scénarios hypothétiques pour rendre le contenu plus accessible et attrayant pour les auditeurs.
234
+
235
+ Gardez à l'esprit que votre podcast doit être accessible à un large public, donc évitez d'utiliser trop de jargon ou de supposer une connaissance préalable du sujet. Si nécessaire, trouvez des moyens d'expliquer brièvement les concepts complexes en termes simples.
236
+
237
+ Utilisez votre imagination pour combler les lacunes du texte d'entrée ou pour poser des questions stimulantes qui pourraient être explorées dans le podcast. L'objectif est de créer un dialogue informatif et divertissant, donc n'hésitez pas à faire preuve de créativité dans votre approche.
238
+
239
+ Définissez clairement tous les termes utilisés et prenez le temps d'expliquer le contexte.
240
+
241
+ Écrivez ici vos idées de brainstorming et une esquisse générale pour le dialogue du podcast. Assurez-vous de noter les principaux points et enseignements que vous souhaitez réitérer à la fin.
242
+
243
+ Faites en sorte que ce soit amusant et captivant.
244
+ """,
245
+ "prelude": """Maintenant que vous avez réfléchi à des idées et créé une esquisse générale, il est temps d'écrire le dialogue réel du podcast. Visez un flux naturel et conversationnel entre l'hôte et tout invité. Intégrez les meilleures idées de votre session de brainstorming et assurez-vous d'expliquer tous les sujets complexes de manière compréhensible.
246
+ """,
247
+ "dialog": """Écrivez ici un dialogue de podcast très long, captivant et informatif, basé sur les points clés et les idées créatives que vous avez développés lors de la session de brainstorming. Utilisez un ton conversationnel et incluez tout contexte ou explication nécessaire pour rendre le contenu accessible à un public général.
248
+
249
+ Ne créez jamais de noms fictifs pour les hôtes et les invités, mais rendez cela engageant et immersif pour les auditeurs. N'incluez pas de marqueurs entre crochets comme [Hôte] ou [Invité]. Conceptionnez votre sortie pour être lue à haute voix – elle sera directement convertie en audio.
250
+
251
+ Faites en sorte que le dialogue soit aussi long et détaillé que possible, tout en restant sur le sujet et en maintenant un flux engageant. Utilisez toute votre capacité de production pour créer l'épisode de podcast le plus long possible, tout en communiquant les informations clés du texte d'entrée de manière divertissante.
252
+
253
+ À la fin du dialogue, l'hôte et les invités doivent naturellement résumer les principales idées et enseignements de leur discussion. Cela doit découler naturellement de la conversation, en réitérant les points clés de manière informelle et conversationnelle. Évitez de donner l'impression qu'il s'agit d'un récapitulatif évident – l'objectif est de renforcer les idées centrales une dernière fois avant de conclure.
254
+
255
+ Le podcast doit comporter environ 20 000 mots.
256
+ """,
257
+ },
258
+
259
+ ################# PODCAST GERMAN ##################
260
+ "podcast (German)": {
261
+ "intro": """Deine Aufgabe ist es, den bereitgestellten Text in einen lebendigen, fesselnden und informativen Podcast-Dialog im Stil von NPR zu verwandeln. Der Eingabetext kann unstrukturiert oder chaotisch sein, da er aus verschiedenen Quellen wie PDFs oder Webseiten stammen kann.
262
+
263
+ Mach dir keine Sorgen über Formatierungsprobleme oder irrelevante Informationen; dein Ziel ist es, die wichtigsten Punkte zu extrahieren, Definitionen und interessante Fakten zu identifizieren, die in einem Podcast besprochen werden könnten.
264
+
265
+ Definiere alle verwendeten Begriffe sorgfältig für ein breites Publikum.
266
+ """,
267
+ "text_instructions": "Lies zuerst den Eingabetext sorgfältig durch und identifiziere die Hauptthemen, Schlüsselpunkte und interessante Fakten oder Anekdoten. Überlege, wie du diese Informationen auf unterhaltsame und ansprechende Weise präsentieren könntest, sodass sie für eine hochwertige Präsentation geeignet sind.",
268
+ "scratch_pad": """Denke kreativ darüber nach, wie du die Hauptthemen und Schlüsselpunkte, die du im Eingabetext identifiziert hast, diskutieren könntest. Verwende Analogien, Beispiele, Erzähltechniken oder hypothetische Szenarien, um den Inhalt für die Zuhörer nachvollziehbarer und ansprechender zu gestalten.
269
+
270
+ Behalte im Hinterkopf, dass dein Podcast einem breiten Publikum zugänglich sein sollte, daher vermeide zu viel Fachjargon oder die Annahme von Vorwissen über das Thema. Falls nötig, überlege dir Möglichkeiten, um komplexe Konzepte kurz und einfach zu erklären.
271
+
272
+ Nutze deine Fantasie, um Lücken im Eingabetext zu füllen oder um nachdenklich stimmende Fragen zu formulieren, die im Podcast erforscht werden könnten. Das Ziel ist es, einen informativen und unterhaltsamen Dialog zu schaffen, daher kannst du bei deinem Ansatz kreativ sein.
273
+
274
+ Definiere alle verwendeten Begriffe klar und nimm dir die Zeit, den Hintergrund zu erläutern.
275
+
276
+ Schreibe deine Brainstorming-Ideen und eine grobe Gliederung für den Podcast-Dialog hier auf. Achte darauf, die wichtigsten Erkenntnisse und Aussagen, die du am Ende wiederholen möchtest, zu notieren.
277
+
278
+ Sorge dafür, dass es unterhaltsam und spannend ist.
279
+ """,
280
+ "prelude": """Nun, da du Ideen gesammelt und eine grobe Gliederung erstellt hast, ist es an der Zeit, den eigentlichen Podcast-Dialog zu schreiben. Strebe einen natürlichen, konversationellen Fluss zwischen dem Moderator und etwaigen Gästen an. Nutze die besten Ideen aus deiner Brainstorming-Sitzung und erkläre alle komplexen Themen auf eine leicht verständliche Weise.
281
+ """,
282
+ "dialog": """Schreibe hier einen sehr langen, fesselnden und informativen Podcast-Dialog, basierend auf den wichtigsten Punkten und kreativen Ideen, die du während der Brainstorming-Sitzung erarbeitet hast. Verwende einen konversationellen Ton und füge alle notwendigen Kontexte oder Erklärungen hinzu, um den Inhalt für ein allgemeines Publikum zugänglich zu machen.
283
+
284
+ Verwende niemals erfundene Namen für die Moderatoren und Gäste, aber gestalte es zu einem fesselnden und immersiven Erlebnis für die Zuhörer. Verwende keine Platzhalter wie [Moderator] oder [Gast]. Dein Output wird direkt in Audio umgewandelt, daher entwerfe den Dialog so, dass er laut vorgelesen werden kann.
285
+
286
+ Gestalte den Dialog so lang und detailliert wie möglich, bleibe dabei jedoch immer beim Thema und erhalte einen flüssigen, ansprechenden Verlauf. Verwende deine volle Output-Kapazität, um die längste mögliche Podcast-Episode zu erstellen, während du die wichtigsten Informationen aus dem Eingabetext auf unterhaltsame Weise vermittelst.
287
+
288
+ Am Ende des Dialogs sollen der Moderator und die Gäste die wichtigsten Erkenntnisse und Aussagen ihres Gesprächs auf natürliche Weise zusammenfassen. Dies sollte organisch aus der Konversation hervorgehen und die wichtigsten Punkte in einem lockeren, gesprächigen Stil wiederholen. Vermeide es, wie eine offensichtliche Zusammenfassung zu klingen – das Ziel ist es, die zentralen Ideen ein letztes Mal zu verstärken, bevor der Podcast endet.
289
+
290
+ Der Podcast sollte etwa 20.000 Wörter umfassen.
291
+ """,
292
+ },
293
+
294
+ ################# PODCAST SPANISH ##################
295
+ "podcast (Spanish)": {
296
+ "intro": """Tu tarea es tomar el texto de entrada proporcionado y convertirlo en un diálogo de podcast animado, atractivo e informativo, al estilo de NPR. El texto de entrada puede estar desordenado o poco estructurado, ya que podría provenir de diversas fuentes como archivos PDF o páginas web.
297
+
298
+ No te preocupes por los problemas de formato o por la información irrelevante; tu objetivo es extraer los puntos clave, identificar definiciones y hechos interesantes que podrían discutirse en un podcast.
299
+
300
+ Define cuidadosamente todos los términos utilizados para una audiencia amplia.
301
+ """,
302
+ "text_instructions": "Primero, lee detenidamente el texto de entrada e identifica los temas principales, los puntos clave y cualquier hecho o anécdota interesante. Piensa en cómo podrías presentar esta información de una manera divertida y atractiva, adecuada para una presentación de alta calidad.",
303
+ "scratch_pad": """Piensa de manera creativa sobre cómo discutir los temas principales y los puntos clave que has identificado en el texto de entrada. Considera usar analogías, ejemplos, técnicas narrativas o escenarios hipotéticos para hacer que el contenido sea más comprensible y atractivo para los oyentes.
304
+
305
+ Ten en cuenta que tu podcast debe ser accesible para una audiencia general, así que evita usar demasiado jerga técnica o asumir que la audiencia tiene conocimientos previos del tema. Si es necesario, piensa en formas de explicar brevemente cualquier concepto complejo en términos sencillos.
306
+
307
+ Usa tu imaginación para llenar los vacíos en el texto de entrada o para formular preguntas provocadoras que podrían explorarse en el podcast. El objetivo es crear un diálogo informativo y entretenido, por lo que puedes ser creativo en tu enfoque.
308
+
309
+ Define claramente todos los términos utilizados y asegúrate de explicar el trasfondo.
310
+
311
+ Escribe tus ideas de brainstorming y un esquema general del diálogo del podcast aquí. Asegúrate de anotar los puntos clave y las conclusiones que deseas reiterar al final.
312
+
313
+ Asegúrate de que sea divertido y emocionante.
314
+ """,
315
+ "prelude": """Ahora que has realizado una lluvia de ideas y has creado un esquema general, es hora de escribir el diálogo real del podcast. Apunta a un flujo natural y conversacional entre el presentador y cualquier invitado. Incorpora las mejores ideas de tu sesión de lluvia de ideas y asegúrate de explicar cualquier tema complejo de una manera fácil de entender.
316
+ """,
317
+ "dialog": """Escribe aquí un diálogo de podcast muy largo, atractivo e informativo, basado en los puntos clave y las ideas creativas que se te ocurrieron durante la sesión de brainstorming. Usa un tono conversacional e incluye el contexto o las explicaciones necesarias para que el contenido sea accesible a una audiencia general.
318
+
319
+ Nunca uses nombres inventados para los presentadores e invitados, pero haz que sea una experiencia atractiva e inmersiva para los oyentes. No incluyas ningún marcador de posición entre corchetes como [Presentador] o [Invitado]. Diseña tu salida para que sea leída en voz alta, ya que se convertirá directamente en audio.
320
+
321
+ Haz el diálogo lo más largo y detallado posible, manteniéndote en el tema y asegurando un flujo atractivo. Apunta a utilizar toda tu capacidad de salida para crear el episodio de podcast más largo posible, mientras comunicas la información clave del texto de entrada de una manera entretenida.
322
+
323
+ Al final del diálogo, el presentador y los invitados deben resumir naturalmente las principales ideas y conclusiones de su conversación. Esto debe fluir orgánicamente desde la conversación, reiterando los puntos clave de manera casual y conversacional. Evita que suene como un resumen obvio: el objetivo es reforzar las ideas centrales una última vez antes de finalizar.
324
+
325
+ El podcast debe tener alrededor de 20,000 palabras.
326
+ """,
327
+ },
328
+
329
+ ################# PODCAST Portuguese ##################
330
+ "podcast (Portuguese)": {
331
+ "intro": """Sua tarefa é pegar o texto de entrada fornecido e transformá-lo em um diálogo de podcast animado, envolvente e informativo, no estilo da NPR. O texto de entrada pode ser desorganizado ou não estruturado, pois pode vir de várias fontes, como PDFs ou páginas da web.
332
+
333
+ Não se preocupe com problemas de formatação ou informações irrelevantes; seu objetivo é extrair os pontos principais, identificar definições e fatos interessantes que possam ser discutidos em um podcast.
334
+
335
+ Defina cuidadosamente todos os termos usados para um público amplo.
336
+ """,
337
+ "text_instructions": "Primeiro, leia atentamente o texto de entrada e identifique os principais tópicos, pontos-chave e quaisquer fatos ou anedotas interessantes. Pense em como você poderia apresentar essas informações de maneira divertida e envolvente, adequada para uma apresentação de alta qualidade.",
338
+ "scratch_pad": """Pense de maneira criativa sobre como discutir os principais tópicos e pontos-chave que você identificou no texto de entrada. Considere usar analogias, exemplos, técnicas de narrativa ou cenários hipotéticos para tornar o conteúdo mais acessível e interessante para os ouvintes.
339
+
340
+ Tenha em mente que seu podcast deve ser acessível a um público geral, por isso, evite usar jargões técnicos ou presumir que o público tem conhecimento prévio do assunto. Se necessário, pense em maneiras de explicar brevemente qualquer conceito complexo em termos simples.
341
+
342
+ Use sua imaginação para preencher quaisquer lacunas no texto de entrada ou para criar perguntas instigantes que possam ser exploradas no podcast. O objetivo é criar um diálogo informativo e divertido, então sinta-se à vontade para ser criativo em sua abordagem.
343
+
344
+ Defina claramente todos os termos utilizados e faça um esforço para explicar o contexto.
345
+
346
+ Escreva suas ideias de brainstorming e um esboço para o diálogo do podcast aqui. Certifique-se de anotar os principais insights e pontos que deseja reiterar no final.
347
+
348
+ Certifique-se de que seja divertido e empolgante.
349
+ """,
350
+ "prelude": """Agora que você já fez um brainstorming de ideias e criou um esboço, é hora de escrever o diálogo real do podcast. Busque um fluxo natural e conversacional entre o apresentador e qualquer convidado. Incorpore as melhores ideias de sua sessão de brainstorming e certifique-se de explicar qualquer tópico complexo de maneira fácil de entender.
351
+ """,
352
+ "dialog": """Escreva aqui um diálogo de podcast muito longo, envolvente e informativo, com base nos pontos-chave e nas ideias criativas que você criou durante a sessão de brainstorming. Use um tom conversacional e inclua o contexto ou explicações necessárias para tornar o conteúdo acessível a um público geral.
353
+
354
+ Nunca use nomes inventados para os apresentadores e convidados, mas faça com que seja uma experiência envolvente e imersiva para os ouvintes. Não inclua marcadores de posição como [Apresentador] ou [Convidado]. Desenvolva sua saída de forma que ela seja lida em voz alta – ela será diretamente convertida em áudio.
355
+
356
+ Faça o diálogo o mais longo e detalhado possível, mantendo-se no tema e garantindo um fluxo envolvente. Use sua capacidade total de produção para criar o episódio de podcast mais longo possível, enquanto comunica as informações principais do texto de entrada de maneira divertida.
357
+
358
+ No final do diálogo, o apresentador e os convidados devem resumir naturalmente as principais ideias e insights de sua conversa. Isso deve fluir organicamente a partir da conversa, reiterando os pontos-chave de maneira casual e conversacional. Evite soar como um resumo óbvio – o objetivo é reforçar as ideias centrais uma última vez antes de finalizar.
359
+
360
+ O podcast deve ter cerca de 20.000 palavras.
361
+ """,
362
+ },
363
+
364
+ ################# PODCAST Hindi ##################
365
+ "podcast (Hindi)": {
366
+ "intro": """आपका कार्य दिए गए इनपुट टेक्स्ट को लेकर उसे एक जीवंत, आकर्षक और जानकारीपूर्ण पॉडकास्ट वार्तालाप में बदलना है, NPR की शैली में। इनपुट टेक्स्ट असंगठित या अव्यवस्थित हो सकता है, क्योंकि यह विभिन्न स्रोतों जैसे PDFs या वेब पेजों से आ सकता है।
367
+
368
+ फ़ॉर्मेटिंग समस्याओं या अप्रासंगिक जानकारी की चिंता न करें; आपका उद्देश्य मुख्य बिंदुओं को निकालना, परिभाषाओं और दिलचस्प तथ्यों को पहचानना है जिन्हें पॉडकास्ट में चर्चा की जा सकती है।
369
+
370
+ सभी उपयोग किए गए शब���दों को सावधानीपूर्वक व्यापक दर्शकों के लिए परिभाषित करें।
371
+ """,
372
+ "text_instructions": "सबसे पहले, इनपुट टेक्स्ट को ध्यान से पढ़ें और मुख्य विषयों, प्रमुख बिंदुओं और किसी भी दिलचस्प तथ्य या उपाख्यानों की पहचान करें। इस जानकारी को प्रस्तुत करने के बारे में सोचें कि आप इसे एक मज़ेदार, आकर्षक तरीके से कैसे प्रस्तुत कर सकते हैं जो उच्च गुणवत्ता वाली प्रस्तुति के लिए उपयुक्त हो।",
373
+ "scratch_pad": """मुख्य विषयों और प्रमुख बिंदुओं पर चर्चा करने के रचनात्मक तरीकों के बारे में सोचें जिन्हें आपने इनपुट टेक्स्ट में पहचाना है। उदाहरणों, कहानियों की तकनीकों, या काल्पनिक परिदृश्यों का उपयोग करके सामग्री को श्रोताओं के लिए अधिक सम्बंधित और आकर्षक बनाने पर विचार करें।
374
+
375
+ ध्यान रखें कि आपका पॉडकास्ट एक सामान्य दर्शक के लिए सुलभ होना चाहिए, इसलिए बहुत अधिक तकनीकी शब्दजाल से बचें या यह न मानें कि विषय का पूर्व ज्ञान है। यदि आवश्यक हो, तो किसी भी जटिल अवधारणा को सरल शब्दों में संक्षेप में समझाने के तरीकों के बारे में सोचें।
376
+
377
+ अपनी कल्पना का उपयोग करके इनपुट टेक्स्ट में किसी भी अंतराल को भरें या पॉडकास्ट में खोजे जा सकने वाले विचारोत्तेजक सवालों के साथ आएं। उद्देश्य एक जानकारीपूर्ण और मनोरंजक वार्तालाप बनाना है, इसलिए अपने दृष्टिकोण में रचनात्मक होने से न डरें।
378
+
379
+ सभी उपयोग किए गए शब्दों को स्पष्ट रूप से परिभाषित करें और पृष्ठभूमि समझाने के लिए समय दें।
380
+
381
+ यहां अपने विचार-मंथन और पॉडकास्ट वार्तालाप के लिए एक मोटा खाका लिखें। सुनिश्चित करें कि आपने उन प्रमुख अंतर्दृष्टियों और निष्कर्षों को नोट किया है जिन्हें आप अंत में दोहराना चाहते हैं।
382
+
383
+ इसे मजेदार और रोमांचक बनाएं।
384
+ """,
385
+ "prelude": """अब जब आपने विचार-मंथन किया है और एक मोटा खाका तैयार कर लिया है, तो वास्तविक पॉडकास्ट वार्तालाप लिखने का समय आ गया है। होस्ट और किसी भी अतिथि वक्ता के बीच एक स्वाभाविक, संवादात्मक प्रवाह की दिशा में कार्य करें। अपने विचार-मंथन सत्र से सर्वश्रेष्ठ विचारों को शामिल करें और सुनिश्चित करें कि किसी भी जटिल विषय को आसानी से समझ में आने वाले तरीके से समझाया जाए।
386
+ """,
387
+ "dialog": """यहां एक बहुत लंबा, आकर्षक और जानकारीपूर्ण पॉडकास्ट वार्तालाप लिखें, जो उन प्रमुख बिंदुओं और रचनात्मक विचारों पर आधारित हो जो आपने विचार-मंथन सत्र के दौरान बनाए थे। एक संवादात्मक शैली का उपयोग करें और सामग्री को एक सामान्य दर्शक के लिए सुलभ बनाने के लिए किसी भी आवश्यक संदर्भ या व्याख्याएं शामिल करें।
388
+
389
+ होस्ट और अतिथि वक्ताओं के लिए कभी भी काल्पनिक नामों का उपयोग न करें, बल्कि श्रोताओं के लिए इसे एक आकर्षक और immersive अनुभव बनाएं। किसी भी प्रकार के ब्रैकेटेड प्लेसहोल्डर्स जैसे [होस्ट] या [अतिथि] को शामिल न करें। अपनी आउटपुट को इस तरह डिज़ाइन करें कि इसे ज़ोर से पढ़ा जा सके – इसे सीधे ऑडियो में परिवर्तित किया जाएगा।
390
+
391
+ डायलॉग को यथासंभव लंबा और विस्तृत बनाएं, फिर भी विषय पर बने रहें और प्रवाह को आकर्षक बनाए रखें। अपनी पूरी आउटपुट क्षमता का उपयोग करते हुए यथासंभव लंबे पॉडकास्ट एपिसोड को बनाएं, जबकि फिर भी इनपुट टेक्स्ट से प्रमुख जानकारी को मनोरंजक तरीके से संप्रेषित करें।
392
+
393
+ वार्तालाप के अंत में, होस्ट और अतिथि वक्ता अपने चर्चा से स्वाभाविक रूप से मुख्य अंतर्दृष्टियों और निष्कर्षों को संक्षेप में प्रस्तुत करें। यह वार्तालाप से स्वाभाविक रूप से प्रवाहित होना चाहिए, अनौपचारिक, संवादात्मक तरीके से प्रमुख बिंदुओं को फिर से स्पष्ट करें। इसे स्पष्ट पुनरावृत्ति की तरह न बनाएं – उद्देश्य केंद्रीय विचारों को एक आखिरी बार सुदृढ़ करना है, इससे पहले कि वार्तालाप समाप्त हो जाए।
394
+
395
+ पॉडकास्ट में लगभग 20,000 शब्द होने चाहिए।
396
+ """,
397
+ },
398
+
399
+ ################# PODCAST Chinese ##################
400
+ "podcast (Chinese)": {
401
+ "intro": """你的任务是将提供的输入文本转变为一个生动、有趣、信息丰富的播客对话,风格类似NPR。输入文本可能是凌乱的或未结构化的,因为它可能来自PDF或网页等各种来源。
402
+
403
+ 不要担心格式问题或任何无关的信息;你的目标是提取关键点,识别定义和可能在播客中讨论的有趣事实。
404
+
405
+ 为广泛的听众仔细定义所有使用的术语。
406
+ """,
407
+ "text_instructions": "首先,仔细阅读输入文本,识别主要话题、关键点和任何有趣的事实或轶事。思考如何以一种有趣且引人入胜的方式呈现这些信息,适合高质量的呈现。",
408
+ "scratch_pad": """集思广益,想出一些讨论你在输入文本中识别到的主要话题和关键点的创意方式。考虑使用类比、例子、讲故事的技巧或假设场景,让内容对听众更具相关性和吸引力。
409
+
410
+ 请记住,你的播客应面向普通大众,因此避免使用过多的行话或假设听众对该主题有预先的了解。如有必要,考虑简要解释任何复杂概念,用简单的术语进行说明。
411
+
412
+ 利用你的想象力填补输入文本中的任何空白,或提出一些值得探索的发人深省的问题。目标是创造一个信息丰富且有趣的对话,因此可以在方法上大胆创新。
413
+
414
+ 明确地定义所有使用的术语,并花时间解释背景。
415
+
416
+ 在这里写下你的头脑风暴想法和播客对话的粗略大纲。务必记录你想在结尾重复的关键见解和收获。
417
+
418
+ 确保让它有趣且令人兴奋。
419
+ """,
420
+ "prelude": """现在你已经进行了头脑风暴并创建了一个粗略大纲,是时候编写实际的播客对话了。目标是主持人与嘉宾之间的自然对话流。结合你头脑风暴中的最佳想法,并确保以简单易懂的方式解释任何复杂的主题。
421
+ """,
422
+ "dialog": """在这里写下一个非常长、引人入胜且信息丰富的播客对话,基于你在头脑风暴会议中提出的关键点和创意。使用对话语气,并包含任何必要的上下文或解释,使内容易于普通听众理解。
423
+
424
+ 不要为主持人和嘉宾使用虚构的名字,而是让听众体验一个引人入胜且沉浸式的经历。不要包括像[主持人]或[嘉宾]这样的占位符。设计你的输出以供大声朗读——它将被直接转换为音频。
425
+
426
+ 使对话尽可能长且详细,同时保持在主题上并维持引人入胜的流畅性。充分利用你的输出能力,创造尽可能长的播客节目,同时以有趣的方式传达输入文本中的关键信息。
427
+
428
+ 在对话的最后,主持人和嘉宾应自然总结他们讨论的主要见解和收获。这应从对话中自然流出,以随意、对话的方式重复关键点。避免显得像是显而易见的总结——目标是在结束前最后一次加强核心思想。
429
+
430
+ 播客应约有20,000字。
431
+ """,
432
+ },
433
+ }
434
+
435
+ # Function to update instruction fields based on template selection
436
+ def update_instructions(template):
437
+ return (
438
+ INSTRUCTION_TEMPLATES[template]["intro"],
439
+ INSTRUCTION_TEMPLATES[template]["text_instructions"],
440
+ INSTRUCTION_TEMPLATES[template]["scratch_pad"],
441
+ INSTRUCTION_TEMPLATES[template]["prelude"],
442
+ INSTRUCTION_TEMPLATES[template]["dialog"]
443
+ )
444
+
445
+ import concurrent.futures as cf
446
+ import glob
447
+ import io
448
+ import os
449
+ import time
450
+ from pathlib import Path
451
+ from tempfile import NamedTemporaryFile
452
+ from typing import List, Literal
453
+
454
+ import gradio as gr
455
+
456
+ from loguru import logger
457
+ from openai import OpenAI
458
+ from promptic import llm
459
+ from pydantic import BaseModel, ValidationError
460
+ from pypdf import PdfReader
461
+ from tenacity import retry, retry_if_exception_type
462
+
463
+ # Define standard values
464
+ STANDARD_TEXT_MODELS = [
465
+ "o1-preview-2024-09-12",
466
+ "o1-preview",
467
+ "gpt-4o-2024-08-06",
468
+ "gpt-4o-mini",
469
+ "o1-mini-2024-09-12",
470
+ "o1-mini",
471
+ "chatgpt-4o-latest",
472
+ "gpt-4-turbo",
473
+ "openai/custom_model",
474
+ ]
475
+
476
+ STANDARD_AUDIO_MODELS = [
477
+ "tts-1",
478
+ "tts-1-hd",
479
+ ]
480
+
481
+ STANDARD_VOICES = [
482
+ "alloy",
483
+ "echo",
484
+ "fable",
485
+ "onyx",
486
+ "nova",
487
+ "shimmer",
488
+ ]
489
+
490
+ class DialogueItem(BaseModel):
491
+ text: str
492
+ speaker: Literal["speaker-1", "speaker-2"]
493
+
494
+ class Dialogue(BaseModel):
495
+ scratchpad: str
496
+ dialogue: List[DialogueItem]
497
+
498
+ def get_mp3(text: str, voice: str, audio_model: str, api_key: str = None) -> bytes:
499
+ client = OpenAI(
500
+ api_key=api_key or os.getenv("OPENAI_API_KEY"),
501
+ )
502
+
503
+ with client.audio.speech.with_streaming_response.create(
504
+ model=audio_model,
505
+ voice=voice,
506
+ input=text,
507
+ ) as response:
508
+ with io.BytesIO() as file:
509
+ for chunk in response.iter_bytes():
510
+ file.write(chunk)
511
+ return file.getvalue()
512
+
513
+
514
+ from functools import wraps
515
+
516
+ def conditional_llm(model, api_base=None, api_key=None):
517
+ """
518
+ Conditionally apply the @llm decorator based on the api_base parameter.
519
+ If api_base is provided, it applies the @llm decorator with api_base.
520
+ Otherwise, it applies the @llm decorator without api_base.
521
+ """
522
+ def decorator(func):
523
+ if api_base:
524
+ return llm(model=model, api_base=api_base)(func)
525
+ else:
526
+ return llm(model=model, api_key=api_key)(func)
527
+ return decorator
528
+
529
+ def generate_audio(
530
+ files: list,
531
+ openai_api_key: str = None,
532
+ text_model: str = "o1-preview-2024-09-12",
533
+ audio_model: str = "tts-1",
534
+ speaker_1_voice: str = "alloy",
535
+ speaker_2_voice: str = "echo",
536
+ api_base: str = None,
537
+ intro_instructions: str = '',
538
+ text_instructions: str = '',
539
+ scratch_pad_instructions: str = '',
540
+ prelude_dialog: str = '',
541
+ podcast_dialog_instructions: str = '',
542
+ edited_transcript: str = None,
543
+ user_feedback: str = None,
544
+ original_text: str = None,
545
+ debug = False,
546
+ ) -> tuple:
547
+ # 讀取環境變數中 OpenAI API Key
548
+ if not openai_api_key:
549
+ openai_api_key = os.getenv("OPENAI_API_KEY")
550
+ if not openai_api_key:
551
+ raise gr.Error("OpenAI API key is required")
552
+
553
+
554
+ combined_text = original_text or ""
555
+
556
+ # If there's no original text, extract it from the uploaded files
557
+ if not combined_text:
558
+ for file in files:
559
+ with Path(file).open("rb") as f:
560
+ reader = PdfReader(f)
561
+ text = "\n\n".join([page.extract_text() for page in reader.pages if page.extract_text()])
562
+ combined_text += text + "\n\n"
563
+
564
+ # Configure the LLM based on selected model and api_base
565
+ @retry(retry=retry_if_exception_type(ValidationError))
566
+ @conditional_llm(model=text_model, api_base=api_base, api_key=openai_api_key)
567
+ def generate_dialogue(text: str, intro_instructions: str, text_instructions: str, scratch_pad_instructions: str,
568
+ prelude_dialog: str, podcast_dialog_instructions: str,
569
+ edited_transcript: str = None, user_feedback: str = None, ) -> Dialogue:
570
+ """
571
+ {intro_instructions}
572
+
573
+ Here is the original input text:
574
+
575
+ <input_text>
576
+ {text}
577
+ </input_text>
578
+
579
+ {text_instructions}
580
+
581
+ <scratchpad>
582
+ {scratch_pad_instructions}
583
+ </scratchpad>
584
+
585
+ {prelude_dialog}
586
+
587
+ <podcast_dialogue>
588
+ {podcast_dialog_instructions}
589
+ </podcast_dialogue>
590
+ {edited_transcript}{user_feedback}
591
+ """
592
+
593
+ instruction_improve='Based on the original text, please generate an improved version of the dialogue by incorporating the edits, comments and feedback.'
594
+ edited_transcript_processed="\nPreviously generated edited transcript, with specific edits and comments that I want you to carefully address:\n"+"<edited_transcript>\n"+edited_transcript+"</edited_transcript>" if edited_transcript !="" else ""
595
+ user_feedback_processed="\nOverall user feedback:\n\n"+user_feedback if user_feedback !="" else ""
596
+
597
+ if edited_transcript_processed.strip()!='' or user_feedback_processed.strip()!='':
598
+ user_feedback_processed="<requested_improvements>"+user_feedback_processed+"\n\n"+instruction_improve+"</requested_improvements>"
599
+
600
+ if debug:
601
+ logger.info (edited_transcript_processed)
602
+ logger.info (user_feedback_processed)
603
+
604
+ # Generate the dialogue using the LLM
605
+ llm_output = generate_dialogue(
606
+ combined_text,
607
+ intro_instructions=intro_instructions,
608
+ text_instructions=text_instructions,
609
+ scratch_pad_instructions=scratch_pad_instructions,
610
+ prelude_dialog=prelude_dialog,
611
+ podcast_dialog_instructions=podcast_dialog_instructions,
612
+ edited_transcript=edited_transcript_processed,
613
+ user_feedback=user_feedback_processed
614
+ )
615
+
616
+ # Generate audio from the transcript
617
+ audio = b""
618
+ transcript = ""
619
+ characters = 0
620
+
621
+ with cf.ThreadPoolExecutor() as executor:
622
+ futures = []
623
+ for line in llm_output.dialogue:
624
+ transcript_line = f"{line.speaker}: {line.text}"
625
+ voice = speaker_1_voice if line.speaker == "speaker-1" else speaker_2_voice
626
+ future = executor.submit(get_mp3, line.text, voice, audio_model, openai_api_key)
627
+ futures.append((future, transcript_line))
628
+ characters += len(line.text)
629
+
630
+ for future, transcript_line in futures:
631
+ audio_chunk = future.result()
632
+ audio += audio_chunk
633
+ transcript += transcript_line + "\n\n"
634
+
635
+ logger.info(f"Generated {characters} characters of audio")
636
+
637
+ temporary_directory = "./gradio_cached_examples/tmp/"
638
+ os.makedirs(temporary_directory, exist_ok=True)
639
+
640
+ # Use a temporary file -- Gradio's audio component doesn't work with raw bytes in Safari
641
+ temporary_file = NamedTemporaryFile(
642
+ dir=temporary_directory,
643
+ delete=False,
644
+ suffix=".mp3",
645
+ )
646
+ temporary_file.write(audio)
647
+ temporary_file.close()
648
+
649
+ # Delete any files in the temp directory that end with .mp3 and are over a day old
650
+ for file in glob.glob(f"{temporary_directory}*.mp3"):
651
+ if os.path.isfile(file) and time.time() - os.path.getmtime(file) > 24 * 60 * 60:
652
+ os.remove(file)
653
+
654
+ return temporary_file.name, transcript, combined_text
655
+
656
+ def validate_and_generate_audio(*args):
657
+ files = args[0]
658
+ if not files:
659
+ return None, None, None, "Please upload at least one PDF file before generating audio."
660
+ try:
661
+ audio_file, transcript, original_text = generate_audio(*args)
662
+ return audio_file, transcript, original_text, None # Return None as the error when successful
663
+ except Exception as e:
664
+ # If an error occurs during generation, return None for the outputs and the error message
665
+ return None, None, None, str(e)
666
+
667
+ def edit_and_regenerate(edited_transcript, user_feedback, *args):
668
+ # Replace the original transcript and feedback in the args with the new ones
669
+ #new_args = list(args)
670
+ #new_args[-2] = edited_transcript # Update edited transcript
671
+ #new_args[-1] = user_feedback # Update user feedback
672
+ return validate_and_generate_audio(*new_args)
673
+
674
+ # New function to handle user feedback and regeneration
675
+ def process_feedback_and_regenerate(feedback, *args):
676
+ # Add user feedback to the args
677
+ new_args = list(args)
678
+ new_args.append(feedback) # Add user feedback as a new argument
679
+ return validate_and_generate_audio(*new_args)
680
+
681
+ with gr.Blocks(title="PDF to Audio", css="""
682
+ #header {
683
+ display: flex;
684
+ align-items: center;
685
+ justify-content: space-between;
686
+ padding: 20px;
687
+ background-color: transparent;
688
+ border-bottom: 1px solid #ddd;
689
+ }
690
+ #title {
691
+ font-size: 24px;
692
+ margin: 0;
693
+ }
694
+ #logo_container {
695
+ width: 200px;
696
+ height: 200px;
697
+ display: flex;
698
+ justify-content: center;
699
+ align-items: center;
700
+ }
701
+ #logo_image {
702
+ max-width: 100%;
703
+ max-height: 100%;
704
+ object-fit: contain;
705
+ }
706
+ #main_container {
707
+ margin-top: 20px;
708
+ }
709
+ """) as demo:
710
+
711
+ with gr.Row(elem_id="header"):
712
+ with gr.Column(scale=4):
713
+ gr.Markdown("# Convert PDFs into an audio podcast, lecture, summary and others\n\nFirst, upload one or more PDFs, select options, then push Generate Audio.\n\nYou can also select a variety of custom option and direct the way the result is generated.", elem_id="title")
714
+ with gr.Column(scale=1):
715
+ gr.HTML('''
716
+ <div id="logo_container">
717
+ <img src="https://huggingface.co/spaces/lamm-mit/PDF2Audio/resolve/main/logo.png" id="logo_image" alt="Logo">
718
+ </div>
719
+ ''')
720
+ #gr.Markdown("")
721
+ submit_btn = gr.Button("Generate Audio", elem_id="submit_btn")
722
+
723
+ with gr.Row(elem_id="main_container"):
724
+ with gr.Column(scale=2):
725
+ files = gr.Files(label="PDFs", file_types=["pdf"], )
726
+
727
+ openai_api_key = gr.Textbox(
728
+ label="OpenAI API Key",
729
+ visible=True, # Always show the API key field
730
+ placeholder="Enter your OpenAI API Key here...",
731
+ type="password" # Hide the API key input
732
+ )
733
+ text_model = gr.Dropdown(
734
+ label="Text Generation Model",
735
+ choices=STANDARD_TEXT_MODELS,
736
+ value="o1-preview-2024-09-12", #"gpt-4o-mini",
737
+ info="Select the model to generate the dialogue text.",
738
+ )
739
+ audio_model = gr.Dropdown(
740
+ label="Audio Generation Model",
741
+ choices=STANDARD_AUDIO_MODELS,
742
+ value="tts-1",
743
+ info="Select the model to generate the audio.",
744
+ )
745
+ speaker_1_voice = gr.Dropdown(
746
+ label="Speaker 1 Voice",
747
+ choices=STANDARD_VOICES,
748
+ value="alloy",
749
+ info="Select the voice for Speaker 1.",
750
+ )
751
+ speaker_2_voice = gr.Dropdown(
752
+ label="Speaker 2 Voice",
753
+ choices=STANDARD_VOICES,
754
+ value="echo",
755
+ info="Select the voice for Speaker 2.",
756
+ )
757
+ api_base = gr.Textbox(
758
+ label="Custom API Base",
759
+ placeholder="Enter custom API base URL if using a custom/local model...",
760
+ info="If you are using a custom or local model, provide the API base URL here, e.g.: http://localhost:8080/v1 for llama.cpp REST server.",
761
+ )
762
+
763
+ with gr.Column(scale=3):
764
+ template_dropdown = gr.Dropdown(
765
+ label="Instruction Template",
766
+ choices=list(INSTRUCTION_TEMPLATES.keys()),
767
+ value="podcast (Chinese)", # 默認選擇中文範本
768
+ info="Select the instruction template to use. You can also edit any of the fields for more tailored results.",
769
+ )
770
+ intro_instructions = gr.Textbox(
771
+ label="Intro Instructions",
772
+ lines=10,
773
+ value=INSTRUCTION_TEMPLATES["podcast (Chinese)"]["intro"], # 使用中文範本中的值
774
+ info="Provide the introductory instructions for generating the dialogue.",
775
+ )
776
+ text_instructions = gr.Textbox(
777
+ label="Standard Text Analysis Instructions",
778
+ lines=10,
779
+ placeholder="Enter text analysis instructions...",
780
+ value=INSTRUCTION_TEMPLATES["podcast"]["text_instructions"],
781
+ info="Provide the instructions for analyzing the raw data and text.",
782
+ )
783
+ scratch_pad_instructions = gr.Textbox(
784
+ label="Scratch Pad Instructions",
785
+ lines=15,
786
+ value=INSTRUCTION_TEMPLATES["podcast"]["scratch_pad"],
787
+ info="Provide the scratch pad instructions for brainstorming presentation/dialogue content.",
788
+ )
789
+ prelude_dialog = gr.Textbox(
790
+ label="Prelude Dialog",
791
+ lines=5,
792
+ value=INSTRUCTION_TEMPLATES["podcast"]["prelude"],
793
+ info="Provide the prelude instructions before the presentation/dialogue is developed.",
794
+ )
795
+ podcast_dialog_instructions = gr.Textbox(
796
+ label="Podcast Dialog Instructions",
797
+ lines=20,
798
+ value=INSTRUCTION_TEMPLATES["podcast"]["dialog"],
799
+ info="Provide the instructions for generating the presentation or podcast dialogue.",
800
+ )
801
+
802
+ audio_output = gr.Audio(label="Audio", format="mp3", interactive=False, autoplay=False)
803
+ transcript_output = gr.Textbox(label="Transcript", lines=20, show_copy_button=True)
804
+ original_text_output = gr.Textbox(label="Original Text", lines=10, visible=False)
805
+ error_output = gr.Textbox(visible=False) # Hidden textbox to store error message
806
+
807
+ use_edited_transcript = gr.Checkbox(label="Use Edited Transcript (check if you want to make edits to the initially generated transcript)", value=False)
808
+ edited_transcript = gr.Textbox(label="Edit Transcript Here. E.g., mark edits in the text with clear instructions. E.g., '[ADD DEFINITION OF MATERIOMICS]'.", lines=20, visible=False,
809
+ show_copy_button=True, interactive=False)
810
+
811
+ user_feedback = gr.Textbox(label="Provide Feedback or Notes", lines=10, #placeholder="Enter your feedback or notes here..."
812
+ )
813
+ regenerate_btn = gr.Button("Regenerate Audio with Edits and Feedback")
814
+ # Function to update the interactive state of edited_transcript
815
+ def update_edit_box(checkbox_value):
816
+ return gr.update(interactive=checkbox_value, lines=20 if checkbox_value else 20, visible=True if checkbox_value else False)
817
+
818
+ # Update the interactive state of edited_transcript when the checkbox is toggled
819
+ use_edited_transcript.change(
820
+ fn=update_edit_box,
821
+ inputs=[use_edited_transcript],
822
+ outputs=[edited_transcript]
823
+ )
824
+ # Update instruction fields when template is changed
825
+ template_dropdown.change(
826
+ fn=update_instructions,
827
+ inputs=[template_dropdown],
828
+ outputs=[intro_instructions, text_instructions, scratch_pad_instructions, prelude_dialog, podcast_dialog_instructions]
829
+ )
830
+
831
+ submit_btn.click(
832
+ fn=validate_and_generate_audio,
833
+ inputs=[
834
+ files, openai_api_key, text_model, audio_model,
835
+ speaker_1_voice, speaker_2_voice, api_base,
836
+ intro_instructions, text_instructions, scratch_pad_instructions,
837
+ prelude_dialog, podcast_dialog_instructions,
838
+ edited_transcript, # placeholder for edited_transcript
839
+ user_feedback, # placeholder for user_feedback
840
+ ],
841
+ outputs=[audio_output, transcript_output, original_text_output, error_output]
842
+ ).then(
843
+ fn=lambda audio, transcript, original_text, error: (
844
+ transcript if transcript else "",
845
+ error if error else None
846
+ ),
847
+ inputs=[audio_output, transcript_output, original_text_output, error_output],
848
+ outputs=[edited_transcript, error_output]
849
+ ).then(
850
+ fn=lambda error: gr.Warning(error) if error else None,
851
+ inputs=[error_output],
852
+ outputs=[]
853
+ )
854
+
855
+ regenerate_btn.click(
856
+ fn=lambda use_edit, edit, *args: validate_and_generate_audio(
857
+ *args[:12], # All inputs up to podcast_dialog_instructions
858
+ edit if use_edit else "", # Use edited transcript if checkbox is checked, otherwise empty string
859
+ *args[12:] # user_feedback and original_text_output
860
+ ),
861
+ inputs=[
862
+ use_edited_transcript, edited_transcript,
863
+ files, openai_api_key, text_model, audio_model,
864
+ speaker_1_voice, speaker_2_voice, api_base,
865
+ intro_instructions, text_instructions, scratch_pad_instructions,
866
+ prelude_dialog, podcast_dialog_instructions,
867
+ user_feedback, original_text_output
868
+ ],
869
+ outputs=[audio_output, transcript_output, original_text_output, error_output]
870
+ ).then(
871
+ fn=lambda audio, transcript, original_text, error: (
872
+ transcript if transcript else "",
873
+ error if error else None
874
+ ),
875
+ inputs=[audio_output, transcript_output, original_text_output, error_output],
876
+ outputs=[edited_transcript, error_output]
877
+ ).then(
878
+ fn=lambda error: gr.Warning(error) if error else None,
879
+ inputs=[error_output],
880
+ outputs=[]
881
+ )
882
+
883
+ # Add README content at the bottom
884
+ gr.Markdown("---") # Horizontal line to separate the interface from README
885
+ gr.Markdown(read_readme())
886
+
887
+ # Enable queueing for better performance
888
+ demo.queue(max_size=20, default_concurrency_limit=32)
889
+
890
+ # Launch the Gradio app
891
+ if __name__ == "__main__":
892
+ demo.launch(share=True)
logo.png ADDED
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ gradio
2
+ pandas
3
+ openai
4
+ pypdf
5
+ loguru
6
+ promptic
7
+ tenacity