This commit is contained in:
jeremygan2021
2026-03-03 23:07:17 +08:00
parent 05f02a1454
commit 0aa8f5f473
7 changed files with 204 additions and 65 deletions

View File

@@ -23,7 +23,7 @@ app = FastAPI()
# 字体文件配置
FONT_FILE = "GB2312-16.bin"
FONT_CHUNK_SIZE = 512
HIGH_FREQ_CHARS = "的一是在不了有和人这中大为上个国我以要他时来用们生到作地于出就分对成会可主发年动同工也能下过子说产种面而方后多定行学法所民得经十三之进着等部度家电力里如水化高自二理起小物现实加量都两体制机当使点从业本去把性好应开它合还因由其些然前外天政四日那社义事平形相全表间样与关各重新线内数正心反你明看原又么利比或但质气第向道命此变条只没结解问意建月公无系军很情者最立代想已通并提直题党程展五果料象员革位入常文总次品式活设及管特件长求老头基资边流路级少图山统接知较将组见计别她手角期根论运农指几九区强放决西被干做必战先回则任取据处队南给色光门即保治北造百规热领七海口东导器压志世金增争济阶油思术极交受联什认六共权收证改清己美再采转更单风切打白教速花带安场身车例真务具万每目至达走积示议声报斗完类八离华名确才科张信马节话米整空元况今集温传土许步群广石记需段研界拉林律叫且究观越织装影算低持音众书布复容儿须际商非验连断深难近矿千周委素技备半办青省列习响约支般史感劳便团往酸历市克何除消构府称太准精值号率族维划选标写存候毛亲快效斯院查江型眼王按格养易置派层片始却专状育厂京识适属圆包火住调满县局照参红细引听该铁价严龙飞"
HIGH_FREQ_CHARS = "的一是在不了有和人这中大为上个国我以要他时来用们生到作地于出就分对成会可主发年动同工也能下过子说产种面而方后多定行学法所民得经十三之进着等部度家电力里如水化高自二理起小物现实加量都两体制机当使点从业本去把性好应开它合还因由其些然前外天政四日那社义事平形相全表间样与关各重新线内数正心反你明看原又么利比或但质气第向道命此变条只没结解问意建月公无系军很情者最立代想已通并提直题党程展五果料象员革位入常文总次品式活设及管特件长求老头基资边流路级少图山统接知较将组见计别她手角期根论运农指几九区强放决西被干做必战先回则任取据处队南给色光门即保治北造百规热领七海口东导器压志世金增争济阶油思术极交受联什认六共权收证改清己美再采转更单风切打白教速花带安场身车例真务具万每目至达走积示议声报斗完类八离华名确才科张信马节话米整空元况今集温传土许步群广石记需段研界拉林律叫且究观越织装影算低持音众书布复容儿须际商非验连断深难近矿千周委素技备半办青省列习响约支般史感劳便团往酸历市克何除消构府称太准精值号率族维划选标写存候毛亲快效斯院查江型眼王按格养易置派层片始却专状育厂京识适属圆包火住调满县局照参红细引听该铁价严龙飞量迹AI贴纸生成连功败请试"
# 高频字对应的Unicode码点列表
HIGH_FREQ_UNICODE = [ord(c) for c in HIGH_FREQ_CHARS]
@@ -428,11 +428,13 @@ class MyRecognitionCallback(RecognitionCallback):
self.loop = loop
self.final_text = "" # 保存最终识别结果
self.sentence_list = [] # 累积所有句子
self.last_send_time = 0 # 上次发送时间
def on_open(self) -> None:
print("ASR Session started")
self.sentence_list = []
self.final_text = ""
self.last_send_time = 0
def on_close(self) -> None:
print("ASR Session closed")
@@ -440,6 +442,15 @@ class MyRecognitionCallback(RecognitionCallback):
if self.sentence_list:
self.final_text = "".join(self.sentence_list)
print(f"Final combined ASR text: {self.final_text}")
# 最后发送一次完整的
try:
if self.loop.is_running():
asyncio.run_coroutine_threadsafe(
self.websocket.send_text(f"ASR:{self.final_text}"),
self.loop
)
except Exception as e:
print(f"Failed to send final ASR result: {e}")
def on_event(self, result: RecognitionResult) -> None:
if result.get_sentence():
@@ -472,15 +483,21 @@ class MyRecognitionCallback(RecognitionCallback):
self.final_text = "".join(self.sentence_list)
print(f"ASR Update: {self.final_text}")
# 用户要求录音时不返回文字,只在结束后返回完整结果
# 所以这里注释掉实时发送逻辑
# 将识别结果发送回客户端
try:
if self.loop.is_running():
asyncio.run_coroutine_threadsafe(
self.websocket.send_text(f"ASR:{self.final_text}"),
self.loop
)
except Exception as e:
print(f"Failed to send ASR result to client: {e}")
# 增加节流机制:每 500ms 发送一次,或者文本长度变化较大时发送
# current_time = time.time()
# if current_time - self.last_send_time > 0.5:
# self.last_send_time = current_time
# try:
# if self.loop.is_running():
# asyncio.run_coroutine_threadsafe(
# self.websocket.send_text(f"ASR:{self.final_text}"),
# self.loop
# )
# except Exception as e:
# print(f"Failed to send ASR result to client: {e}")
def process_chunk_32_to_16(chunk_bytes, gain=1.0):
processed_chunk = bytearray()
@@ -666,9 +683,10 @@ def generate_image(prompt, progress_callback=None, retry_count=0, max_retries=2)
g6 = (g >> 2) & 0x3F
b5 = (b >> 3) & 0x1F
# 大端模式:高字节在前 (符合ST7789默认配置)
rgb565 = (r5 << 11) | (g6 << 5) | b5
rgb565_data.extend(struct.pack('>H', rgb565))
# Pack as Big Endian (>H) which is standard for SPI displays
# BGR565: Blue(5) Green(6) Red(5)
bgr565 = (b5 << 11) | (g6 << 5) | r5
rgb565_data.extend(struct.pack('>H', bgr565))
# 保存为.bin文件
with open(GENERATED_THUMB_FILE, 'wb') as f:
@@ -830,20 +848,30 @@ async def websocket_endpoint(websocket: WebSocket):
except Exception as e:
print(f"Error converting to MP3: {e}")
# 4. 如果有识别结果,调用文生图API生成图片
# 4. 如果有识别结果,发送ASR文字到ESP32
if asr_text:
print(f"Generating image for: {asr_text}")
# 先发送 ASR 文字到 ESP32 显示
print(f"ASR result: {asr_text}")
# 发送 ASR 文字到 ESP32 显示
await websocket.send_text(f"ASR:{asr_text}")
# 使用 create_task 异步执行,避免阻塞主循环处理字体请求
asyncio.create_task(start_async_image_generation(websocket, asr_text))
# 以前自动生成图片的逻辑已移除
# 等待客户端发送 GENERATE_IMAGE 指令
else:
print("No ASR text, skipping image generation")
print("No ASR text")
# 如果没有文字也通知一下避免UI卡在某个状态
# await websocket.send_text("ASR:")
print("Server processing finished.")
elif text.startswith("GENERATE_IMAGE:"):
# 收到生成图片指令
prompt_text = text.split(":", 1)[1]
print(f"Received GENERATE_IMAGE request: {prompt_text}")
if prompt_text:
asyncio.create_task(start_async_image_generation(websocket, prompt_text))
else:
await websocket.send_text("STATUS:ERROR:提示词为空")
elif text.startswith("GET_TASK_STATUS:"):
task_id = text.split(":", 1)[1].strip()
if task_id in active_tasks: