-
-
Notifications
You must be signed in to change notification settings - Fork 623
Open
Labels
bugSomething isn't workingSomething isn't working
Description
Description
I am running an assistant. and i need to include the resource where the information has been found .
the problem this dos not work when you send the very first message!
private function streamResponse($client, $threadId, $runParameters ,$chat_title)
{
return response()->stream(function () use ($client, $threadId, $runParameters, $chat_title) {
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
$runResponse = $client->threads()->runs()->createStreamed($threadId, $runParameters);
$currentMessageId = null;
$buffer = '';
$messageRunMap = [];
$currentRunId = null;
$currentSources = [];
$citedFileIds = [];
// Get all runs for this thread to build the file mapping
$runs = $client->threads()->runs()->list($threadId);
if (!empty($runs['data'])) {
foreach ($runs['data'] as $run) {
$stepsResponse = $client->threads()->runs()->steps()->list(
threadId: $threadId,
runId: $run['id']
);
$messageRunMap[$run['id']] = $this->buildFileNameMap($stepsResponse->toArray());
}
}
foreach ($runResponse as $response) {
switch ($response->event) {
case 'thread.run.created':
$currentRunId = $response->response->id;
break;
case 'thread.message.delta':
if ($response->response->delta->content) {
foreach ($response->response->delta->content as $content) {
if ($content->type === 'text' && !empty($content->text->value)) {
if (empty($currentMessageId)) {
$currentMessageId = $response->response->id;
}
// Check for file citations in annotations
if (!empty($content->text->annotations)) {
foreach ($content->text->annotations as $annotation) {
if ($annotation->type === 'file_citation' && !empty($annotation->fileCitation->fileId)) {
$fileId = $annotation->fileCitation->fileId;
$citedFileIds[] = $fileId;
// Find the source name in messageRunMap
foreach ($messageRunMap as $runSources) {
if (isset($runSources[$fileId])) {
$currentSources[] = $runSources[$fileId];
break;
}
}
}
}
}
// Clean and add content to buffer
$buffer .= $this->cleanCitationMarkers($content->text->value);
// Split buffer into chunks at natural break points
$chunks = preg_split('/(?<=[\.\!\?\s])/u', $buffer, -1, PREG_SPLIT_NO_EMPTY);
if (count($chunks) >= 1) {
$buffer = array_pop($chunks);
foreach ($chunks as $chunk) {
$chunk = trim($chunk);
if (empty($chunk)) {
continue;
}
// Check if this chunk starts with a number followed by a dot
$startsWithNumber = preg_match('/^\d+\./', $chunk);
// Add <br> before numbered items
if ($startsWithNumber) {
$chunk = "<br>" . $chunk;
}
// Add <br> after chunks ending with period (but not for numbered items)
if (str_ends_with($chunk, '.')) {
// Check if the chunk ends with a number followed by a dot (e.g., "1.")
if (!preg_match('/\d+\.$/', $chunk)) {
$chunk .= "<br>";
}
}
/* if (empty($currentSources)) {
$currentSources[] = "القانون السعودي";
$currentSources[] = "القانون السعودي 2";
}*/
echo "data: " . json_encode([
'title' => $chat_title,
'content' => $chunk,
'sources' => array_values(array_unique($currentSources))
], JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR) . "\n\n";
ob_flush();
flush();
usleep(50000);
}
}
}
}
}
break;
case 'thread.run.completed':
// Always send the final buffer content, even if empty
echo "data: " . json_encode([
'title' => $chat_title,
'content' => $buffer,
'sources' => array_values(array_unique($currentSources))
], JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR) . "\n\n";
break;
case 'thread.run.requires_action':
// Handle tool calls if needed
break;
case 'thread.run.failed':
echo "data: " . json_encode([
'error' => 'Run failed'
]) . "\n\n";
break;
}
}
}, 200, [
'Cache-Control' => 'no-cache',
'Content-Type' => 'text/event-stream',
'Connection' => 'keep-alive',
'X-Accel-Buffering' => 'no'
]);
}
private function buildFileNameMap($steps)
{
static $cache = [];
$cacheKey = md5(serialize($steps));
if (isset($cache[$cacheKey])) {
return $cache[$cacheKey];
}
$fileNameMap = [];
if (isset($steps['data'])) {
foreach ($steps['data'] as $step) {
if ($step['type'] === 'tool_calls' &&
isset($step['step_details']['tool_calls'])) {
foreach ($step['step_details']['tool_calls'] as $toolCall) {
if (isset($toolCall['file_search']['results'])) {
foreach ($toolCall['file_search']['results'] as $result) {
if (isset($result['file_id']) && isset($result['file_name'])) {
$fileNameMap[$result['file_id']] = str_replace(
'_',
' ',
basename($result['file_name'], '.txt')
);
}
}
}
}
}
}
}
$cache[$cacheKey] = $fileNameMap;
return $fileNameMap;
}
Steps To Reproduce
Please read the code , you will understand the flow.
OpenAI PHP Client Version
latest one
PHP Version
8.3
Notes
No response
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working