import os
assert os.getenv("OPENAI_API_KEY"), \
"Please set the OPEAI_API_KEY environment variable with your OpenAI API key."01 OpenAI + Timestamp
“Yerevan basement, dates back 200 years. There are canvases in the basement now. It’s an art place.” լուսանկարի հղումը, Հեղինակ՝ Ashkhen Gevorgyan
📌 Նկարագիր
OpenAI-ը ChatGPT-ն ստեղծող կամպանյան ա։ էսօր սովորելու ենք թե ինչ բան ա API-ը ու ոնց կարանք request-ներ անենք (էս թեմային մի քիչ առնչվել ենք deepl-ով թարմանություններ անելիս): Նաև սովորում ենք environment variable-ների գաղափարը (տերմինալի հրամանակ աշխատացնելով ենք անում դասի ժամանակ, ավելի լավ ա dotenv-ով անել, տես վիդեոն)։
OpenAI-ով նայում ենք թե ոնց ա կարելի տեքստեր/նկարներ/աուդիո գեներացնել ու ոնց ա կարելի ֆիքսել թե ինչ կառուցվածքով պատասխանի մեզ api-ը (մի քիչ էլ առնչվում ենք pydantic-ի հետ, որը հետո ենք անցնելու)։
Որպես կիրառություն սարքում ենք ծրագիր որը youtube-ի վիդեո ստանալով քաշում ա իրա տռանսրիպտը (արել էինք նախորդ դասին) ու գենեռացնում ա timestamp-եր (կարևոր թեմաները որ վարկյաններին են սկսվում)
📺 Տեսանյութեր
🏡 Տնային
Կրեատիվությունն ա միակ լիմիտը։ Մի աշխարհ բան ա կարելի անել OpenAI-ով (հայերենի համար ավելի լավ ա Claude-ով անել բայց), կարաք գլխից նաև Streamlit app սարքեք։
📚 Նյութը
OpenAI
First of all pip install openai
Creating API Key
- https://platform.openai.com/settings/organization/api-keys
- https://platform.openai.com/docs/overview
SET OPENAI_API_KEY=sk-...
or
SETX OPENAI_API_KEY "sk-..." # saves it permanentlyLinux/Mac:
export OPENAI_API_KEY="sk-..."With Python:
import os
os.environ["OPENAI_API_KEY"] = "sk-..."MAKE SURE TO ALWAYS KEEP YOUR API KEY SECRET! (REMOVE IT FROM YOUR CODE BEFORE SHARING IT)
Or better use python-dotenv package to load it from .env file, see this lecture for more details.
OpenAI API
Regular Text Completion
!uv pip install dotenvUsing Python 3.11.13 environment at: c:\Users\hayk_\OneDrive\Desktop\01_python_math_ml_course\ma
Resolved 2 packages in 475ms
Prepared 1 package in 51ms
Installed 2 packages in 234ms
+ dotenv==0.9.9
+ python-dotenv==1.1.1
import os
from dotenv import load_dotenv
load_dotenv(override=True)
from openai import OpenAI
client = OpenAI(
# This is the default and can be omitted
api_key=os.getenv("OPENAI_API_KEY"),
)response = client.responses.create(
model="gpt-4o",
instructions="You are a professional youtube chapter and timestamp generator. I will provide you with a transcript of a video, and you will generate timestamps for the key points discussed in the video. The timestamps should be in the format 'HH:MM:SS' and should be accompanied by a brief description of the content at that timestamp.",
input="In this video, we will explore the fascinating world of quantum computing. We will start by discussing the basic principles of quantum mechanics and how they differ from classical physics. Then, we will delve into the concept of qubits and how they are used in quantum computers. We will also cover the challenges faced in building practical quantum computers and the potential applications of this technology in various fields such as cryptography, drug discovery, and artificial intelligence. Finally, we will look at some of the leading companies and research institutions working on quantum computing and their latest advancements.",
)
response.output[0].content[0].text'Certainly! Here are the timestamps and descriptions based on your summary:\n\n- **00:00:05 Introduction to Quantum Computing**\n - Overview of the video’s focus on quantum computing.\n\n- **00:00:30 Basics of Quantum Mechanics**\n - Explanation of basic principles and differences from classical physics.\n\n- **00:01:15 Understanding Qubits**\n - Introduction to qubits and their role in quantum computers.\n\n- **00:02:00 Challenges in Quantum Computing**\n - Discussion of the obstacles in developing practical quantum computers.\n\n- **00:03:00 Applications of Quantum Technology**\n - Exploration of potential uses in cryptography, drug discovery, and AI.\n\n- **00:04:00 Leading Players in Quantum Research**\n - Overview of key companies and institutions advancing in quantum computing.\n\n- **00:05:00 Recent Advancements in Quantum Computing**\n - Insights into the latest developments in the field.'
type(response)openai.types.responses.response.Response
response.output[0].content[0].text'Certainly! Here are the timestamps and descriptions based on your summary:\n\n- **00:00:05 Introduction to Quantum Computing**\n - Overview of the video’s focus on quantum computing.\n\n- **00:00:30 Basics of Quantum Mechanics**\n - Explanation of basic principles and differences from classical physics.\n\n- **00:01:15 Understanding Qubits**\n - Introduction to qubits and their role in quantum computers.\n\n- **00:02:00 Challenges in Quantum Computing**\n - Discussion of the obstacles in developing practical quantum computers.\n\n- **00:03:00 Applications of Quantum Technology**\n - Exploration of potential uses in cryptography, drug discovery, and AI.\n\n- **00:04:00 Leading Players in Quantum Research**\n - Overview of key companies and institutions advancing in quantum computing.\n\n- **00:05:00 Recent Advancements in Quantum Computing**\n - Insights into the latest developments in the field.'
Image
from openai import OpenAI
import base64
client = OpenAI()
response = client.responses.create(
model="gpt-4.1-mini",
input="Generate a Ghibli style image of cheese",
tools=[{"type": "image_generation"}],
)
# Save the image to a file
image_data = [
output.result
for output in response.output
if output.type == "image_generation_call"
]
if image_data:
image_base64 = image_data[0]
with open("cheese.png", "wb") as f:
f.write(base64.b64decode(image_base64))--------------------------------------------------------------------------- PermissionDeniedError Traceback (most recent call last) Cell In[30], line 6 2 import base64 4 client = OpenAI() ----> 6 response = client.responses.create( 7 model="gpt-4.1-mini", 8 input="Generate a Ghibli style image of cheese", 9 tools=[{"type": "image_generation"}], 10 ) 12 # Save the image to a file 13 image_data = [ 14 output.result 15 for output in response.output 16 if output.type == "image_generation_call" 17 ] File c:\Users\hayk_\OneDrive\Desktop\01_python_math_ml_course\ma\Lib\site-packages\openai\resources\responses\responses.py:840, in Responses.create(self, background, conversation, include, input, instructions, max_output_tokens, max_tool_calls, metadata, model, parallel_tool_calls, previous_response_id, prompt, prompt_cache_key, reasoning, safety_identifier, service_tier, store, stream, stream_options, temperature, text, tool_choice, tools, top_logprobs, top_p, truncation, user, extra_headers, extra_query, extra_body, timeout) 803 def create( 804 self, 805 *, (...) 838 timeout: float | httpx.Timeout | None | NotGiven = not_given, 839 ) -> Response | Stream[ResponseStreamEvent]: --> 840 return self._post( 841 "/responses", 842 body=maybe_transform( 843 { 844 "background": background, 845 "conversation": conversation, 846 "include": include, 847 "input": input, 848 "instructions": instructions, 849 "max_output_tokens": max_output_tokens, 850 "max_tool_calls": max_tool_calls, 851 "metadata": metadata, 852 "model": model, 853 "parallel_tool_calls": parallel_tool_calls, 854 "previous_response_id": previous_response_id, 855 "prompt": prompt, 856 "prompt_cache_key": prompt_cache_key, 857 "reasoning": reasoning, 858 "safety_identifier": safety_identifier, 859 "service_tier": service_tier, 860 "store": store, 861 "stream": stream, 862 "stream_options": stream_options, 863 "temperature": temperature, 864 "text": text, 865 "tool_choice": tool_choice, 866 "tools": tools, 867 "top_logprobs": top_logprobs, 868 "top_p": top_p, 869 "truncation": truncation, 870 "user": user, 871 }, 872 response_create_params.ResponseCreateParamsStreaming 873 if stream 874 else response_create_params.ResponseCreateParamsNonStreaming, 875 ), 876 options=make_request_options( 877 extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout 878 ), 879 cast_to=Response, 880 stream=stream or False, 881 stream_cls=Stream[ResponseStreamEvent], 882 ) File c:\Users\hayk_\OneDrive\Desktop\01_python_math_ml_course\ma\Lib\site-packages\openai\_base_client.py:1259, in SyncAPIClient.post(self, path, cast_to, body, options, files, stream, stream_cls) 1245 def post( 1246 self, 1247 path: str, (...) 1254 stream_cls: type[_StreamT] | None = None, 1255 ) -> ResponseT | _StreamT: 1256 opts = FinalRequestOptions.construct( 1257 method="post", url=path, json_data=body, files=to_httpx_files(files), **options 1258 ) -> 1259 return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) File c:\Users\hayk_\OneDrive\Desktop\01_python_math_ml_course\ma\Lib\site-packages\openai\_base_client.py:1047, in SyncAPIClient.request(self, cast_to, options, stream, stream_cls) 1044 err.response.read() 1046 log.debug("Re-raising status error") -> 1047 raise self._make_status_error_from_response(err.response) from None 1049 break 1051 assert response is not None, "could not resolve response (should never happen)" PermissionDeniedError: Error code: 403 - {'error': {'message': 'Your organization must be verified to use the model `gpt-4.1-mini`. Please go to: https://platform.openai.com/settings/organization/general and click on Verify Organization. If you just verified, it can take up to 15 minutes for access to propagate.', 'type': 'invalid_request_error', 'param': None, 'code': None}}
result.data[0].b64_jsonresult.data[0]from openai import OpenAI
import base64
client = OpenAI()
prompt = """
Generate a Jibiri style image of cheese.
"""
result = client.images.generate(
model="dall-e-2",
prompt=prompt
)
image_base64 = result.data[0].b64_json
if image_base64 is None:
print(result.data[0].url)
# image_bytes = base64.b64decode(image_base64)
# # Save the image to a file
# with open("cheese.png", "wb") as f:
# f.write(image_bytes)https://oaidalleapiprodscus.blob.core.windows.net/private/org-ttpmtIE2I4svAF3GF4fDbAI6/user-ikPOmBgtK5dBqbZAFApYEkzD/img-0TlF85LchVIVmZQUwCFy2hfH.png?st=2025-10-25T05%3A43%3A00Z&se=2025-10-25T07%3A43%3A00Z&sp=r&sv=2024-08-04&sr=b&rscd=inline&rsct=image/png&skoid=77e5a8ec-6bd1-4477-8afc-16703a64f029&sktid=a48cca56-e6da-484e-a814-9c849652bcb3&skt=2025-10-25T05%3A58%3A11Z&ske=2025-10-26T05%3A58%3A11Z&sks=b&skv=2024-08-04&sig=tni3EYmj1ztC214h/Lxv0drMR6POb9CAV4y%2BOA5ENv8%3D
# get image from url
import requests
response = requests.get(result.data[0].url)
# Save the image to a file
with open("cheese.png", "wb") as f:
f.write(response.content)Audio
import base64
from openai import OpenAI
client = OpenAI()
completion = client.chat.completions.create(
model="gpt-4o-audio-preview",
modalities=["text", "audio"],
audio={"voice": "alloy", "format": "wav"},
messages=[
{
"role": "user",
"content": "What is the best cheese in Armenia?"
}
]
)
# print(completion.choices[0])
wav_bytes = base64.b64decode(completion.choices[0].message.audio.data)
with open("dog.wav", "wb") as f:
f.write(wav_bytes)Structured output
summary -
main_idea -
Transcription - [timestamp, text]
{
"summary": ...
"main_idea": ...,
}
["summary"]from pydantic import BaseModel
from openai import OpenAI
client = OpenAI()
class CalendarEvent(BaseModel):
name: str
date: str
participants: list[str]
messages_lst = [
{"role": "system", "content": "Extract the event information."},
{"role": "user", "content": "Alice and Bob are going to a science fair on Friday."},
]
completion = client.chat.completions.parse(
model="gpt-4o-2024-08-06",
messages=messages_lst,
response_format=CalendarEvent,
)
event = completion.choices[0].message.parsedevent.participants['Alice', 'Bob']
History
messages_lst.append(
{
"role": "assistant",
"content": f"Event Name: {event.name}, Date: {event.date}, Participants: {', '.join(event.participants)}"
}
)
messages_lst.append(
{
"role": "user",
"content": f"Output the date in ISO format"
}
)messages_lst[{'role': 'system', 'content': 'Extract the event information.'},
{'role': 'user',
'content': 'Alice and Bob are going to a science fair on Friday.'},
{'role': 'assistant',
'content': 'Event Name: Science Fair, Date: Friday, Participants: Alice, Bob'},
{'role': 'user', 'content': 'Output the date in ISO format'}]
completion = client.chat.completions.parse(
model="gpt-4o-2024-08-06",
messages=messages_lst,
response_format=CalendarEvent,
)
# event = completion.choices#[0].message.parsedCell In[53], line 8 print(completion.choices#[0].message.parsed) ^ SyntaxError: incomplete input
completion.choices[0].message.parsedCalendarEvent(name='Science Fair', date='2023-09-29', participants=['Alice', 'Bob'])
🛠️ Գործնական
Timestamp generator
from typing import List
from pytubefix import YouTube
from datetime import datetime
from dataclasses import dataclass@dataclass()
class VideoInfo:
video_id: str
title: str
keywords: List[str]
publish_date: str
length_seconds: int
@staticmethod
def get_days_since_publish(publish_date) -> int:
if isinstance(publish_date, datetime):
publish_date = publish_date.strftime("%Y-%m-%d")
publish_date = datetime.strptime(publish_date, "%Y-%m-%d")
current_date = datetime.now()
return (current_date - publish_date).days
def __post_init__(self):
if not isinstance(self.video_id, str):
raise ValueError("video_id must be a string")
if not isinstance(self.length_seconds, int):
raise ValueError("length_seconds must be an integer")
self.days_since_publish = self.get_days_since_publish(self.publish_date)class YouTubeVideo:
def __init__(self, url: str):
self.video = YouTube(url)
def get_metadata(self) -> VideoInfo:
return VideoInfo(
video_id=self.video.video_id,
title=self.video.title,
keywords=self.video.keywords,
publish_date=self.video.publish_date,
length_seconds=self.video.length
)
def get_transcript(self, language: str = "de", _format = "txt") -> str:
print(f"Fetching transcript for language: {language}")
print(f"Available languages: {self.video.captions.keys()}")
captions = self.video.captions.get(language)
if not captions:
raise ValueError(f"No captions available for language: {language}")
if _format == "txt":
self.text = captions.generate_txt_captions()
elif _format == "srt":
self.text = captions.generate_srt_captions()
else:
raise ValueError(f"Unsupported format: {_format}. Supported formats are 'txt' and 'srt'.")
return self.text
def download_transcript(self, language: str = "de", title: str = "transcript", output_path: str = "transcript.txt") -> None:
captions = self.video.captions.get(language)
if not captions:
raise ValueError(f"No captions available for language: {language}")
captions.download(title=title, output_path=output_path)
vid = YouTubeVideo("https://youtu.be/nU3fzO94lBw")
metadata = vid.get_metadata()transcript = vid.get_transcript(language="a.hy", _format="srt")Fetching transcript for language: a.hy
Available languages: KeysView({'a.hy': <Caption lang="Armenian (auto-generated)" code="a.hy">})
response = client.responses.create(
model="gpt-4o",
instructions="You are a professional youtube chapter and timestamp generator. I will provide you with a transcript of a video, and you will generate timestamps for the key points discussed in the video. The timestamps should be in the format 'HH:MM:SS' and should be accompanied by a brief description of the content at that timestamp. The descriptions should be in the same language as the transcript.",
input=transcript,
)
response.output[0].content[0].text'00:00:00 - **Ծիրանների հաշվարկ**: Խոսք ծիրանների և խնձորների քանակի վրա: \n00:00:12 - **Խնձորների հաշվարկ**: Ուսումնասիրում ենք խնձորների թիվը: \n00:00:26 - **Համեմատություն**: Քննարկում ենք խնձորների և ծիրանների քանակի համեմատությունը: \n00:00:56 - **Մաթեմատիկական պատկերացում**: Ներդրվում է բնական թվերի բազմության գաղափարը: \n00:01:18 - **0-ից 1 միջակայքը**: Քննարկվում է 0-ից 1 թվերի միջակայքի գաղափարը: \n00:01:40 - **Համեմատական վերլուծություն**: Ուսումնասիրում ենք երկու հավաքածուների հզորությունները: \n00:02:43 - **Հավասարության գաղափար**: Հնարավորությունը n-ի և 0-1 միջակայքի հավասարության: \n00:04:00 - **Հահաքանակների օրինակ**: Նորից հայտարարերը, բայց այս անգամ ռուսերեն: \n00:05:40 - **Անվերջության քննարկում**: Ինչպես համեմատել երկու անվերջությունների: \n00:07:16 - **Անհամապատասխանություն**: Բացատրում, որ տարերի թվի հաշվարկն անհնար է 0-1 միջակայքի համար: \n00:11:04 - **Անվերջություն ավելի շատ է**: Հասկանում ենք, որ 0-1 միջակայքը պարունակում է ավելի շատ թվեր քան բնական թվերը: \n00:12:15 - **Եզրափակիչ խոսքեր**: Հրավիրում ենք դիտելու Գիլբերտի հյուրանոցի խնդիրը: \n\nՀիշեցում բոլոր կետերում ավելի մանրամասն քննարկումը տեսնել մեկնաբանություններում:'
print(response.output[0].content[0].text)00:00:00 - **Ծիրանների հաշվարկ**: Խոսք ծիրանների և խնձորների քանակի վրա:
00:00:12 - **Խնձորների հաշվարկ**: Ուսումնասիրում ենք խնձորների թիվը:
00:00:26 - **Համեմատություն**: Քննարկում ենք խնձորների և ծիրանների քանակի համեմատությունը:
00:00:56 - **Մաթեմատիկական պատկերացում**: Ներդրվում է բնական թվերի բազմության գաղափարը:
00:01:18 - **0-ից 1 միջակայքը**: Քննարկվում է 0-ից 1 թվերի միջակայքի գաղափարը:
00:01:40 - **Համեմատական վերլուծություն**: Ուսումնասիրում ենք երկու հավաքածուների հզորությունները:
00:02:43 - **Հավասարության գաղափար**: Հնարավորությունը n-ի և 0-1 միջակայքի հավասարության:
00:04:00 - **Հահաքանակների օրինակ**: Նորից հայտարարերը, բայց այս անգամ ռուսերեն:
00:05:40 - **Անվերջության քննարկում**: Ինչպես համեմատել երկու անվերջությունների:
00:07:16 - **Անհամապատասխանություն**: Բացատրում, որ տարերի թվի հաշվարկն անհնար է 0-1 միջակայքի համար:
00:11:04 - **Անվերջություն ավելի շատ է**: Հասկանում ենք, որ 0-1 միջակայքը պարունակում է ավելի շատ թվեր քան բնական թվերը:
00:12:15 - **Եզրափակիչ խոսքեր**: Հրավիրում ենք դիտելու Գիլբերտի հյուրանոցի խնդիրը:
Հիշեցում բոլոր կետերում ավելի մանրամասն քննարկումը տեսնել մեկնաբանություններում:
Streamlit - environment variable setup🎲 19 (01)
- ▶️Alex Yemenidjian (WCIT speech)
- 🎲Random link
- 🇦🇲🎶C-rouge (Արի’, իմ սոխակ)
- 🌐🎶Pink Floyd (Dark side of the moon)
- 🤌Կարգին
Նշում։ Floyd-ենք ոչ թե երգեր են գրել, այլ ալբոմներ, նենց որ անարդար չի ամբողջ ալբոմը դնելը :-)
