Gradio Python — передача значений компонентов в функцию и обновление интерфейсаPython

Программы на Python
Anonymous
Gradio Python — передача значений компонентов в функцию и обновление интерфейса

Сообщение Anonymous »

Я пытаюсь реализовать приложение Gradio, которое принимает JSON-файл разговора между пользователями и ИИ. Входной json отформатирован таким образом, что существует несколько диалогов, каждый из которых имеет связанный набор возможных ответов от ИИ:

Код: Выделить всё

[
{
"conversations": [
{
"from": "human",
"value": "query"
}
],
"responses": [
{
"from": "gpt",
"value": "response1"
},
{
"from": "gpt",
"value": "response2"
}
]
},
{
"conversations": [
{
"from": "human",
"value": "query"
}
],
"responses": [
{
"from": "gpt",
"value": "response1"
},
{
"from": "gpt",
"value": "response2"
}
]
}
]
Моя цель — создать набор переключателей для каждого из возможных ответов ИИ и собрать эти ответы так, чтобы я мог создать выходной json как таковой, где каждый ответ ИИ имеет поле «предпочтений» в зависимости от того, что выбрано на кнопке «Градио»:

Код: Выделить всё

[
{
"conversations": [
{
"from": "human",
"value": "query"
}
],
"responses": [
{
"from": "gpt",
"value": "response1"
"preference": "Indifferent/Like/Dislike"
},
{
"from": "gpt",
"value": "response2"
"preference": "Indifferent/Like/Dislike"
}
]
},
{
"conversations": [
{
"from": "human",
"value": "query"
}
],
"responses": [
{
"from": "gpt",
"value": "response1"
"preference": "Indifferent/Like/Dislike"
},
{
"from": "gpt",
"value": "response2"
"preference":  "Indifferent/Like/Dislike"
}
]
}
]
Однако моя текущая реализация дает следующую обратную трассировку:

Код: Выделить всё

Traceback (most recent call last):
File "C:\Users\aland\AppData\Local\Programs\Python\Python312\Lib\site-packages\gradio\queueing.py", line 532, in process_events
response = await route_utils.call_process_api(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\aland\AppData\Local\Programs\Python\Python312\Lib\site-packages\gradio\route_utils.py", line 276, in call_process_api
output = await app.get_blocks().process_api(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\aland\AppData\Local\Programs\Python\Python312\Lib\site-packages\gradio\blocks.py", line 1928, in process_api
result = await self.call_function(
^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\aland\AppData\Local\Programs\Python\Python312\Lib\site-packages\gradio\blocks.py", line 1514, in call_function
prediction = await anyio.to_thread.run_sync(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\aland\AppData\Local\Programs\Python\Python312\Lib\site-packages\anyio\to_thread.py", line 56, in run_sync
return await get_async_backend().run_sync_in_worker_thread(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\aland\AppData\Local\Programs\Python\Python312\Lib\site-packages\anyio\_backends\_asyncio.py", line 2177, in run_sync_in_worker_thread
return await future
^^^^^^^^^^^^
File "C:\Users\aland\AppData\Local\Programs\Python\Python312\Lib\site-packages\anyio\_backends\_asyncio.py", line 859, in run
result = context.run(func, *args)
^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\aland\AppData\Local\Programs\Python\Python312\Lib\site-packages\gradio\utils.py", line 832, in wrapper
response = f(*args, **kwargs)
^^^^^^^^^^^^^^^^^^
File "C:\Users\aland\pyproject\Gradio\userfb.py", line 50, in save_feedback_json
json.dump(json_out, tmp_file, indent=4)
File "C:\Users\aland\AppData\Local\Programs\Python\Python312\Lib\json\__init__.py", line 179, in dump
for chunk in iterable:
File "C:\Users\aland\AppData\Local\Programs\Python\Python312\Lib\json\encoder.py", line 430, in _iterencode
yield from _iterencode_list(o, _current_indent_level)
File "C:\Users\aland\AppData\Local\Programs\Python\Python312\Lib\json\encoder.py", line 326, in _iterencode_list
yield from chunks
File "C:\Users\aland\AppData\Local\Programs\Python\Python312\Lib\json\encoder.py", line 406, in _iterencode_dict
yield from chunks
File "C:\Users\aland\AppData\Local\Programs\Python\Python312\Lib\json\encoder.py", line 326, in _iterencode_list
yield from chunks
File "C:\Users\aland\AppData\Local\Programs\Python\Python312\Lib\json\encoder.py", line 406, in _iterencode_dict
yield from chunks
File "C:\Users\aland\AppData\Local\Programs\Python\Python312\Lib\json\encoder.py", line 439, in _iterencode
o = _default(o)
^^^^^^^^^^^
File "C:\Users\aland\AppData\Local\Programs\Python\Python312\Lib\json\encoder.py", line 180, in default
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type Radio is not JSON serializable
Обратите внимание, что основная проблема не в том, что JSON не является сериализуемым, а в том, что я получаю список компонентов вместо списка значений, которые каждый из компонентов держать. В результате я сейчас пытаюсь сериализовать кнопки компонентов, отсюда и ошибка (что не входит в мои намерения). Для начала не должно быть необходимости в сериализации.
Это возникает, когда я пытаюсь запустить строку кода json.dump(json_out, tmp_file, indent=4) , что является попыткой сериализовать информацию в формат json.
  • Насколько я знаю, в своем коде я использую переменные состояния для сбора компонентов обратной связи, которые я хочу проверить. . Однако при передаче в функцию save_feedback_json они передаются как сами компоненты, а не как значения, которые затем не становятся сериализуемыми. Я посчитал это разумным результатом, поскольку эта переменная представляет собой переменную gradio.State, а не список реальных компонентов. Есть ли способ собрать значения этих переменных либо путем рефакторинга кода, чтобы на входе был список компонентов, либо с помощью какого-либо механизма сбора значений компонентов?

    Кроме того, небольшой побочный вопрос: как обновить отображение интерфейса Gradio всякий раз, когда я нажимаю кнопку «Загрузить» для отправленного json? Поскольку я создаю разное количество компонентов Markdown и Radio, я не знаю, есть ли способ объединить эти выходные поля.
    Вот код для справки:

Код: Выделить всё

import gradio as gr
import json
import tempfile

conversation_json = []
feedback_components = []
components = []
uploaded_json = []

def load_conversations(uploaded_json):
components = []
feedback_components = []
for convo in uploaded_json:
user_response=convo["conversations"][0]
user_md = gr.Markdown(f"**{user_response['from']}**: {user_response['value']}")
components.append(user_md)
for response in convo["responses"]:
res_md = gr.Markdown(f"**{response['from']}**: {response['value']}")
components.append(res_md)
fb = gr.Radio(["Like", "Dislike"], label="Feedback", type="value", value="Indifferent", interactive=True)
components.append(fb)
feedback_components.append(fb)
return components, feedback_components

def upload_conversation(file_obj):
with open(file_obj, 'r') as f:
uploaded_json=json.load(f)
return uploaded_json

def save_feedback_json(conversation_json, feedback_values):
json_out = []
fb_ind = 0

for entry in conversation_json:
c_entry = {"conversations": entry["conversations"], "responses": []}
for res in entry["responses"]:
print(fb_ind)
c_entry["responses"].append({
"from": res["from"],
"value": res["value"],
"preference": feedback_values[fb_ind]})
fb_ind += 1
json_out.append(c_entry)

with tempfile.NamedTemporaryFile(delete=False, suffix=".json", mode="w", encoding="utf-8") as tmp_file:
json.dump(json_out, tmp_file, indent=4)
tmp_file_path = tmp_file.name

return tmp_file_path

with gr.Blocks() as iface:
file_input = gr.File(label="Upload JSON files of conversation", file_types=["json"])
json_state = gr.State()
components_display = gr.State()  # Use a container to dynamically display components
feedback_components = gr.State()

file_input.change(upload_conversation, inputs=[file_input], outputs=[json_state])

upload_btn = gr.Button("Load Conversations")
upload_btn.click(load_conversations, inputs=[json_state], outputs=[components_display, feedback_components])

submit_btn = gr.Button("Submit")
feedback_json = gr.File(label="Download JSON")
submit_btn.click(save_feedback_json, inputs=[json_state, feedback_components], outputs=[feedback_json])

iface.launch()
Я создал глобальную переменную для Feedback_comComponents, которая объединяет все компоненты обратной связи, а затем попытался передать ее в функцию save_feedback_json. Это работало только тогда, когда у меня был статический путь к файлу json как таковой:

Код: Выделить всё

import gradio as gr
import json
import tempfile

conversation_json = []
feedback_components = []

def load_conversations(file_name):
with open(file_name, 'r') as f:
conversation_json=json.load(f)

components = []
feedback_components = []
for convo in conversation_json:
user_response=convo["conversations"][0]
components.append(gr.Markdown(f"**{user_response['from']}**: {user_response['value']}"))
for response in convo["responses"]:
components.append(gr.Markdown(f"**{response['from']}**: {response['value']}"))
fb = gr.Radio(["Like", "Dislike"], label="Feedback", type="value", value="Indifferent", interactive=True)
components.append(fb)
feedback_components.append(fb)
return conversation_json, feedback_components, components

def save_feedback_json(*feedback_values):
json_out = []
fb_ind = 0

for entry in conversation_json:
c_entry = {"conversations": entry["conversations"], "responses": []}
for res in entry["responses"]:
c_entry["responses"].append({
"from": res["from"],
"value": res["value"],
"preference": feedback_values[fb_ind]})
fb_ind += 1
json_out.append(c_entry)

with tempfile.NamedTemporaryFile(delete=False, suffix=".json", mode="w", encoding="utf-8") as tmp_file:
json.dump(json_out, tmp_file, indent=4)
tmp_file_path = tmp_file.name

return tmp_file_path

with gr.Blocks() as iface:
conversation_json, feedback_components, components = load_conversations("./data/example_in.json")   # change path here
with gr.Row():
with gr.Column():
for component in components:
if not component.render:
component.render()
submit = gr.Button("Submit",  variant="primary", interactive=True)
#submit.click(save_feedback_json, inputs = feedback_components)
json_output = gr.File(label="Download JSON", interactive=True)
submit.click(
fn=save_feedback_json,
inputs=feedback_components,
outputs=json_output
)
iface.launch()
Однако это не работает в версии «json-uploading», поскольку Feedback_values ​​описывается как пустой кортеж, когда я передаю Feedback_values.
Для второй проблемы, рендеринга, я попробовал вернуть gr.update() и просто попытаться выполнить повторный рендеринг с помощью вложенных операторов with, описанных выше, но ни один из них на самом деле не обновляет интерфейс.
Я В целом, будучи новичком в Gradio, мой код очень беспорядочный, и мне не хватает базовых знаний о том, как Gradio работает под поверхностью. Мы будем очень признательны за любые указания по рефакторингу, советы и подсказки, поскольку я подумываю просто перезапустить свой код, поскольку у меня такой беспорядок.

Подробнее здесь: https://stackoverflow.com/questions/786 ... -interface

Вернуться в «Python»