При разработке пайплайна генерации видеоконтента мне нужно было контролировать максимальную длину сгенерированного текста, чтобы итоговое видео не получилось слишком длинным.
Какие есть способы это сделать? Например, можно задать максимальное количество слов для сгенерированного текста. Если ты хочешь оттолкнуться от длины видео в минутах, используй формулу: video length in minutes = number of words * average reading speed per minute. Средняя скорость чтения — около 100–120 слов в минуту (для английского).
А что насчёт взаимодействия с самой нейросетью? Есть два основных подхода:
Подход первый: явно указать в промпте, что сгенерированный текст не должен превышать определённое количество символов. Обычно это работает лишь посредственно, и я бы не рекомендовал полагаться только на этот метод. Также лучше указать допустимую погрешность, чтобы нейросеть не запуталась.
Подход второй: задать параметр max_tokens, который ограничивает вывод нейросети. Вместе с этим я также рекомендую передавать параметр temperature со значением в диапазоне 0.5–0.8, чтобы нейросеть была более конкретной в ответах и менее многословной.
import re
from src.types import LanguageType
classTextUtils: END_SENTENCE_CHARS =(".","!","?",",",";","。","\n") RATIO ={"en":1.4,"ru":1.6,"es":1.6,"de":1.6,"zh":2.0,"ja":2.0,"ko":2.0,}@staticmethoddefget_tokens_per_word(language: LanguageType)->float: value = TextUtils.RATIO.get(language)ifnot value:raise ValueError(f"Unsupported language: {language}")return value
@staticmethoddefsplit_by_tokens(text:str, max_tokens:int, overlap_tokens:int=0):"""
Разбивает текст на куски по max_tokens токенов с перекрытием overlap_tokens.
Использует tiktoken (cl100k_base).
"""if max_tokens <=0:raise ValueError("max_tokens must be > 0")if overlap_tokens <0:raise ValueError("overlap_tokens must be >= 0")import tiktoken
enc = tiktoken.get_encoding("cl100k_base") tokens = enc.encode(text) chunks =[] start =0 n =len(tokens)while start < n: end =min(start + max_tokens, n) chunk_tokens = tokens[start:end] chunks.append(enc.decode(chunk_tokens))if end >= n:break start = end - overlap_tokens if overlap_tokens >0else end
return chunks
@staticmethoddefgroup_text_into_sentences( text:str, max_words_length:int|None=20)->list[list[dict]]: new_sent_split_pattern ="|".join(map(re.escape, TextUtils.END_SENTENCE_CHARS)) raw =[w.strip()for w in re.split(new_sent_split_pattern, text)if w.strip()] replacements ={"#":"","---":""} raw =[{"word": TextUtils.replace(w, replacements)}for w in raw if w.strip()]return TextUtils.group_words_dict_into_sentences(raw, max_words_length)@staticmethoddefreplace(value:str, replacements:dict)->str:for old, new in replacements.items(): value = value.replace(old, new)return value
@staticmethoddefgroup_words_dict_into_sentences( words:list[dict], max_words_length:int|None=20,)->list[list[dict]]: sentences =[] current_sentence =[]for _, word inenumerate(words): current_sentence.append(word) has_end_char =( word.get("word","").strip().endswith(TextUtils.END_SENTENCE_CHARS)) current_sentence_words ="".join([w.get("word","")for w in current_sentence if w.get("word")]) is_length_exceeded =( max_words_length andlen(current_sentence_words)>= max_words_length
) should_split = has_end_char or is_length_exceeded
# Create new sentence every max_words_per_line words or at punctuationif should_split: sentences.append(current_sentence) current_sentence =[]# Add remaining words if anyif current_sentence: sentences.append(current_sentence)return sentences
# agent example with setting of those parametersdefget_agent(self, words_to_generate:int=300, language: LanguageType ="en"):return AtomicAgent[ VisualSubtitlesMakerInputSchema, VisualSubtitlesMakerOutputSchema,]( config=AgentConfig( client=instructor.from_openai(self.client, mode=instructor.Mode.JSON), model=Config.gpt_model(), model_api_parameters=ModelApiConfig.get_tokens_limit_for_words( words_to_generate, language
), system_prompt_generator=SystemPromptGenerator( background=["""Ты — режиссёр-постановщик кинематографичного фильма.""","""На основе истории из субтитров ты должен создать атмосферные и визуально разнообразные сцены.""",], steps=["""Для каждой сцены сделай одно визуальное описание:
- Ключевое действие/объект сцены
- Обстановка (место, атмосфера, время)
- Эмоции/настроение
""",], output_instructions=["""Пиши в стиле промта для генерации изображений (cinematic).""","""Не добавляй слайды с призывами подписаться, лайкать или комментировать.""",],),))
Как рассчитать количество токенов на основе количества слов? Ниже код, который делает это для четырёх языков. В среднем одно слово на английском равно 1.3 токена. Если передать дробное число, нейросеть молча проигнорирует это и решит, что ограничений нет, что может слить твой баланс. Хорошая идея — проверять результаты, сгенерированные нейросетью, постфактум. С помощью скрипта ниже мне удалось добиться точности свыше 90%. Оставляй комментарии и делись своим опытом. Удачи в разработке!
Содержание
Открыт для работы по контракту
Я доступен для работы по контракту. Если у вас есть интересная идея проекта — запишитесь на звонок через Calendly.