User: import gradio as gr
import os
import sys
import json 
import requests
import random


MODEL = "gpt-4o-mini"
API_URL = os.getenv("API_URL")
DISABLED = os.getenv("DISABLED") == 'True'
OPENAI_API_KEYS = os.getenv("OPENAI_API_KEYS").split(',')
print (API_URL)
print (OPENAI_API_KEYS)
NUM_THREADS = int(os.getenv("NUM_THREADS"))

print (NUM_THREADS)

def exception_handler(exception_type, exception, traceback):
    print("%s: %s" % (exception_type.__name__, exception))
sys.excepthook = exception_handler
sys.tracebacklimit = 0
    
def predict(inputs, top_p, temperature, chat_counter, chatbot, history, request:gr.Request):
    payload = {
        "model": MODEL,
        "messages": [{"role": "user", "content": f"{inputs}"}],
        "temperature": temperature,
        "top_p": top_p,
        "n" : 1,
        "stream": True,
        "presence_penalty":0,
        "frequency_penalty":0,
    }
    OPENAI_API_KEY = random.choice(OPENAI_API_KEYS)
    print (OPENAI_API_KEY)
    headers_dict = {key.decode('utf-8'): value.decode('utf-8') for key, value in request.headers.raw}
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {OPENAI_API_KEY}",
        "Headers": f"{headers_dict}"
    }

    # print(f"chat_counter - {chat_counter}")
    if chat_counter != 0 :
        messages = []
        for i, data in enumerate(history):
            if i % 2 == 0:
                role = 'user'
            else:
                role = 'assistant'
            message = {}
            message["role"] = role
            message["content"] = data
            messages.append(message)
        
        message = {}
        message["role"] = "user" 
        message["content"] = inputs
        messages.append(message)
        payload = {
            "model": MODEL,
            "messages": messages,
            "temperature" : temperature,
            "top_p": top_p,
            "n" : 1,
            "stream": True,
            "presence_penalty":0,
            "frequency_penalty":0,
        }

    chat_counter += 1

    history.append(inputs)
    token_counter = 0 
    partial_words = "" 
    counter = 0

    try:
        # make a POST request to the API endpoint using the requests.post method, passing in stream=True
        response = requests.post(API_URL, headers=headers, json=payload, stream=True)
        response_code = f"{response}"
        #if response_code.strip() != "<Response [200]>":
        #    #print(f"response code - {response}")
        #    raise Exception(f"Sorry, hitting rate limit. Please try again later. {response}")
        
        for chunk in response.iter_lines():
            #print (chunk)
            #sys.stdout.flush()
            #Skipping first chunk
            if counter == 0:
                counter += 1
                continue
                #counter+=1
            # check whether each line is non-empty
            if chunk.decode() :
                chunk = chunk.decode()
                # decode each line as response data is in bytes
                if len(chunk) > 12 and "content" in json.loads(chunk[6:])['choices'][0]['delta']:
                    partial_words = partial_words + json.loads(chunk[6:])['choices'][0]["delta"]["content"]
                    if token_counter == 0:
                        history.append(" " + partial_words)
                    else:
                        history[-1] = partial_words
                    token_counter += 1
                    yield [(history[i], history[i + 1]) for i in range(0, len(history) - 1, 2) ], history, chat_counter, response, gr.update(interactive=False), gr.update(interactive=False)  # resembles {chatbot: chat, state: history}  
    except Exception as e:
        print (f'error found: {e}')
    yield [(history[i], history[i + 1]) for i in range(0, len(history) - 1, 2) ], history, chat_counter, response, gr.update(interactive=True), gr.update(interactive=True)
    print(json.dumps({"chat_counter": chat_counter, "payload": payload, "partial_words": partial_words, "token_counter": token_counter, "counter": counter}))
                   

def reset_textbox():
    return gr.update(value='', interactive=False), gr.update(interactive=False)

title = """<h1 align="center">GPT-4o Mini: Research Preview (Short-Term Availability)</h1>"""
if DISABLED:
    title = """<h1 align="center" style="color:red">This app has reached OpenAI's usage limit. Please check back tomorrow.</h1>"""
description = """Language models can be conditioned to act like dialogue agents through a conversational prompt that typically takes the form:
```
User: <utterance>
Assistant: <utterance>
User: <utterance>
Assistant: <utterance>
...
```
In this app, you can explore the outputs of a gpt-4 turbo LLM.
"""

theme = gr.themes.Default(primary_hue="green")                

with gr.Blocks(css = """#col_container { margin-left: auto; margin-right: auto;}
                #chatbot {height: 520px; overflow: auto;}""",
              theme=theme) as demo:
    gr.HTML(title)
    gr.HTML("""<h3 align="center">This app provides you full access to GPT-4o mini (128K token limit). You don't need any OPENAI API key.</h3>""")

    #gr.HTML('''<center><a href="https://huggingface.co/spaces/ysharma/ChatGPT4?duplicate=true"><img src="https://bit.ly/3gLdBN6" alt="Duplicate Space"></a>Duplicate the Space and run securely with your OpenAI API Key</center>''')
    with gr.Column(elem_id = "col_container", visible=False) as main_block:
        #GPT4 API Key is provided by Huggingface 
        #openai_api_key = gr.Textbox(type='password', label="Enter only your GPT4 OpenAI API key here")
        chatbot = gr.Chatbot(elem_id='chatbot') #c
        inputs = gr.Textbox(placeholder= "Hi there!", label= "Type an input and press Enter") #t
        state = gr.State([]) #s
        with gr.Row():
            with gr.Column(scale=7):
                b1 = gr.Button(visible=not DISABLED) #.style(full_width=True)
            with gr.Column(scale=3):
                server_status_code = gr.Textbox(label="Status code from OpenAI server", )
    
        #inputs, top_p, temperature, top_k, repetition_penalty
        with gr.Accordion("Parameters", open=False):
            top_p = gr.Slider( minimum=-0, maximum=1.0, value=1.0, step=0.05, interactive=True, label="Top-p (nucleus sampling)",)
            temperature = gr.Slider( minimum=-0, maximum=5.0, value=1.0, step=0.1, interactive=True, label="Temperature",)
            #top_k = gr.Slider( minimum=1, maximum=50, value=4, step=1, interactive=True, label="Top-k",)
            #repetition_penalty = gr.Slider( minimum=0.1, maximum=3.0, value=1.03, step=0.01, interactive=True, label="Repetition Penalty", )
            chat_counter = gr.Number(value=0, visible=False, precision=0)
    
    with gr.Column(elem_id = "user_consent_container") as user_consent_block:
        # Get user consent
        accept_checkbox = gr.Checkbox(visible=False)
        js = "(x) => confirm('By clicking \"OK\", I agree that my data may be published or shared.')"
        with gr.Accordion("User Consent for Data Collection, Use, and Sharing", open=True):
            gr.HTML("""
            <div>
                <p>By using our app, which is powered by OpenAI's API, you acknowledge and agree to the following terms regarding the data you provide:</p>
                <ol>
                    <li><strong>Collection:</strong> We may collect information, including the inputs you type into our app, the outputs generated by OpenAI's API, and certain technical details about your device and connection (such as browser type, operating system, and IP address) provided by your device's request headers.</li>
                    <li><strong>Use:</strong> We may use the collected data for research purposes, to improve our services, and to develop new products or services, including commercial applications, and for security purposes, such as protecting against unauthorized access and attacks.</li>
                    <li><strong>Sharing and Publication:</strong> Your data, including the technical details collected from your device's request headers, may be published, shared with third parties, or used for analysis and reporting purposes.</li>
                    <li><strong>Data Retention:</strong> We may retain your data, including the technical details collected from your device's request headers, for as long as necessary.</li>
                </ol>
                <p>By continuing to use our app, you provide your explicit consent to the collection, use, and potential sharing of your data as described above. If you do not agree with our data collection, use, and sharing practices, please do not use our app.</p>
            </div>
            """)
            accept_button = gr.Button("I Agree")

        def enable_inputs():
            return gr.update(visible=False), gr.update(visible=True)

    accept_button.click(None, None, accept_checkbox, js=js, queue=False)
    accept_checkbox.change(fn=enable_inputs, inputs=[], outputs=[user_consent_block, main_block], queue=False)

    inputs.submit(reset_textbox, [], [inputs, b1], queue=False)
    inputs.submit(predict, [inputs, top_p, temperature, chat_counter, chatbot, state], [chatbot, state, chat_counter, server_status_code, inputs, b1],)  #openai_api_key
    b1.click(reset_textbox, [], [inputs, b1], queue=False)
    b1.click(predict, [inputs, top_p, temperature, chat_counter, chatbot, state], [chatbot, state, chat_counter, server_status_code, inputs, b1],)  #openai_api_key
             
    demo.queue(max_size=10, default_concurrency_limit=NUM_THREADS, api_open=False).launch(share=False)

Что делает этот код?
Assistant:  код представляет собой веб-приложение, созданное с использованием библиотеки Gradio, которое позволяет пользователям взаимодействовать с языковой моделью GPT-4. Давайте разберем основные компоненты и функционал этого кода.

### Основные функции:

1. **Импорт необходимых библиотек**: Код начинает с импорта библиотек, таких как `os`, `sys`, `json`, `requests`, и `random`, которые облегчают работу с переменными окружения, HTTP-запросами и генерацией случайных чисел.

2. **Переменные окружения**: 
   - `API_URL`: URL конечной точки API, на которую будут отправляться запросы.
   - `DISABLED`: Флаг, указывающий, доступно ли приложение в данный момент.
   - `OPENAI_API_KEYS`: Список API-ключей OpenAI, из которого будет случайным образом выбран один для выполнения запросов.
   - `NUM_THREADS`: Количество потоков, которые могут одновременно обрабатывать запросы.

3. **Обработка исключений**: Определена функция `exception_handler`, которая перехватывает и выводит информацию об исключениях, возникающих во время работы программы.

4. **Функция `predict`**: Эта основная функция обрабатывает поступающие сообщения от пользователя и взаимодействует с API OpenAI для получения ответов от модели. Она:
   - Формирует запрос с параметрами модели, такими как температуру и `top_p`.
   - Перебирает историю сообщений и формирует структуру данных для передачи в API.
   - Отправляет запрос в формате JSON и обрабатывает ответ в потоковом режиме, выводя частичные ответы по мере их получения.

5. **Графический интерфейс**: 
   - Создан пользовательский интерфейс с использованием библиотеки Gradio, который включает в себя элементы, такие как текстовое поле для ввода, область для отображения чата, кнопки и слайдеры для параметров, влияющих на генерацию текста.
   - Выводится заголовок и описание приложения.
   - Включены параметры, такие как `top_p` и `temperature`, для регулирования генерации текста.

6. **Параметры и управление состоянием**: 
   - Приложение сохраняет историю общения (ввод пользователя и ответы модели) для обработки следующего запроса.
   - Обрабатывается пользовательское согласие на сбор и использование данных при первом запуске.

7. **Запуск приложения**: Приложение запускается в конце скрипта с помощью метода `launch()`, который позволяет пользователю взаимодействовать с интерфейсом.

### Что это приложение делает:
Приложение позволяет пользователю напрямую взаимодействовать с языковой моделью GPT-4 (или ее разновидностью) через веб-интерфейс, где они могут вводить текстовые сообщения и получать ответы в реальном времени. Оно также учитывает различные параметры генерации текста для настройки поведения модели, тем самым обеспечивая более персонализированное взаимодействие. 

### Важно:
Если переменная окружения `DISABLED` равна `True`, интерфейс отображает сообщение о том, что приложение временно недоступно. Для успешного использования требуется, чтобы `API_URL` и API-ключи OpenAI были настроены корректно.
User: os - что это за модуль?
Assistant: `os` — это встроенный модуль в Python, предоставляющий множество функций для взаимодействия с операционной системой. Он предоставляет интерфейс для выполнения операций, связанных с файловой системой, управления процессами и работы с окружением. Вот некоторые основные возможности, которые предлагает модуль `os`:

1. **Работа с файловой системой**:
   - Получение текущего рабочего каталога с помощью `os.getcwd()`.
   - Изменение рабочего каталога с помощью `os.chdir(path)`.
   - Создание новых директорий с помощью `os.mkdir(path)` или `os.makedirs(path)`.
   - Удаление файлов и каталогов с помощью `os.remove(path)` и `os.rmdir(path)` (или `os.removedirs(path)` для рекурсивного удаления).

2. **Хождение по файловой системе**:
   - Перебор файлов и каталогов в директории с помощью `os.listdir(path)` или `os.walk(top)`.

3. **Работа с путями**:
   - Соединение различных частей пути с помощью `os.path.join()`.
   - Проверка существования файлов или директорий с помощью `os.path.exists(path)`.

4. **Переменные окружения**:
   - Доступ к переменным окружения с помощью `os.environ`, что позволяет получить или установить переменные окружения, например, `os.getenv("VARIABLE_NAME")`.

5. **Процесс**:
   - Запуск новых процессов и выполнение команд через `os.system(command)` или `os.exec*()`.

6. **Платформозависимые функции**:
   - Модуль `os` предоставляет функции, специфичные для операционной системы, такие как `os.name`, которая позволяет определить, используется ли Windows, macOS, Linux и т.д.

Таким образом, `os` является важным инструментом для выполнения операций на уровне операционной системы из Python, позволяя разработчикам создавать более сложные и взаимодействующие приложения.
User: os.getenv("API_URL") это что?
Assistant: os.getenv("API_URL")` — это функция из модуля `os`, которая используется для получения значения переменной окружения с именем `API_URL`. 

### Как это работает:

- **Переменные окружения**: Переменные окружения — это значения, которые хранятся в операционной системе и могут использоваться приложениями для конфигурации. Они часто используются для хранения конфиденциальных данных, таких как API-ключи, параметры подключения к базе данных или URL-адреса конечных точек API, чтобы не хранить их в коде напрямую.

- **Функция `os.getenv()`**: Эта функция принимает имя переменной окружения в качестве аргумента и возвращает ее значение. Если переменная окружения не существует, то `os.getenv()` вернет `None` (или можно указать значение по умолчанию, передав второй аргумент).

Пример использования:

```python
import os

api_url = os.getenv("API_URL")
if api_url:
    print(f"API URL is: {api_url}")
else:
    print("API URL is not set")
```

### В вашем коде:
В коде, который вы предоставили, `os.getenv("API_URL")` используется для извлечения значения переменной окружения `API_URL`, чтобы затем использовать его как конечную точку (URL) для выполнения запросов к API OpenAI. Это позволяет конфигурировать приложение без изменения исходного кода, просто изменяя значения переменных окружения в среде, где оно запущено.
User: # Create and activate Python environment
python -m venv env
source env/bin/activate

что это такое
Assistant: анды, которые вы привели, относятся к созданию и активации виртуальной среды Python. Вот пошаговое объяснение того, что каждая из этих команд делает:

1. **Создание виртуальной среды**:
   ```bash
   python -m venv env
   ```
   - **`python -m venv`**: Это команда запускает модуль `venv`, встроенный в Python, для создания виртуальной среды. Виртуальная среда предоставляет изолированное пространство для установки пакетов Python, что позволяет избежать конфликтов между библиотеками и их версиями в различных проектах.
   - **`env`**: Это имя для создаваемой виртуальной среды. Вы можете называть ее любым именем, но "env" часто используется как общий выбор. После выполнения этой команды будет создана директория с именем "env", в которой будут храниться файлы виртуальной среды.

2. **Активация виртуальной среды**:
   ```bash
   source env/bin/activate
   ```
   - **`source`**: Эта команда используется в Unix-подобных системах (таких как Linux и macOS) для выполнения скрипта или активации виртуальной среды.
   - **`env/bin/activate`**: Это путь к исполняемому файлу активации виртуальной среды. Активация среды изменяет командную строку, добавляя префикс с именем виртуальной среды, чтобы вы знали, что вы находитесь в изолированном окружении. Также это позволяет Python и pip использовать пакеты, установленные только в этой среде.

После выполнения этих команд вы находитесь в виртуальной среде, и все установленные пакеты с помощью `pip` будут помещены в эту среду, а не в глобальную установку Python. Это особенно полезно для управления зависимостями вашего проекта и для предотвращения конфликтов версий библиотек.

### Примечание:
- Для Windows команды для активации виртуальной среды будут немного иными:
  ```bash
  .\env\Scripts\activate
  ```
- Чтобы деактивировать виртуальную среду и вернуться к глобальной версии Python, просто выполните команду `deactivate`.
User: (env) f:\Python\Projects\Huggingface\ChatGPT>pip install -r requirements.txt
ERROR: Could not open requirements file: [Errno 2] No such file or directory: 'requirements.txt'
WARNING: You are using pip version 21.2.3; however, version 25.0.1 is available.
You should consider upgrading via the 'f:\Python\Projects\Huggingface\ChatGPT\env\Scripts\python.exe -m pip install --upgrade pip' command.
Assistant: