DEBUG  Error sending message: [TypeError: (0, _openaiService.fetchAIRespon(...)rror);setIsTyping(false);}).then is not a function (it is undefined)]
 DEBUG  Streaming error: {"headers": {"_map": {"": "", "access-control-allow-origin": "*", "cache-control": "public, max-age=31536000, immutable", "content-length": "420", "content-type": "text/plain; charset=utf-8", "date": "Sun, 06 Oct 2024 15:01:31 GMT", "etag": "W/\"1a4-nEJBIWh0qe99bOjUud+m3JDb1vI\"", "via": "1.1 c8cf1dadf4d664882ee6d56cd59205be.cloudfront.net (CloudFront)", "x-amz-cf-id": "XmwqNOTdgnoxD-ajvTltMhcQgcTTc9PqJiu_STDTY_s7GxqWfEMwxw==", "x-amz-cf-pop": "SOF50-P2", "x-cache": "Miss from cloudfront", "x-powered-by": "Express"}}, "status": 200, "statusText": undefined, "target": {"_close": [Function close], "_listeners": {}, "headers": {"Content-Type": "application/json"}, "onerror": [Function anonymous], "onmessage": [Function anonymous], "onopen": undefined, "readyState": 2, "url": "https://text.pollinations.ai/openai", "withCredentials": false}, "type": "error"}
 ERROR  EventSource's response has a Content-Type specifying an unsupported type: text/plain; charset=utf-8. Aborting the connection.


 bu hatayı düzeltmeme yardım et. 

// src/services/openaiService.ts
import axios from 'axios';
import { EventSourcePolyfill } from 'event-source-polyfill';

interface Message {
  role: 'system' | 'user' | 'assistant';
  content: string;
}

interface OpenAIResponse {
  choices: {
    message: {
      role: string;
      content: string;
    };
  }[];
}

// Normal response
export const fetchAIResponse = async (messages: Message[]): Promise<string> => {
  try {
    const response = await axios.post<OpenAIResponse>('https://text.pollinations.ai/openai', {
      model: "gpt-3.5-turbo",
      messages: messages,
    }, {
      headers: {
        'Content-Type': 'application/json',
      },
    });

    console.debug('OpenAI API response:', response.data);
    const aiMessage = response.data.choices[0].message.content;
    return aiMessage;
  } catch (error) {
    console.debug('OpenAI API error:', error);
    return "Üzgünüm, şu anda bir hata yaşandı. Lütfen daha sonra tekrar deneyin.";
  }
};

// Streaming destekliyorsa
export const fetchAIResponseStream = (
  messages: Message[],
  onMessage: (text: string) => void,
  onError: (error: any) => void
) => {
  const OPENAI_ENDPOINT = 'https://text.pollinations.ai/openai';

  const eventSource = new EventSourcePolyfill(OPENAI_ENDPOINT, {
    headers: {
      'Content-Type': 'application/json',
    },
    payload: JSON.stringify({
      model: "gpt-3.5-turbo",
      messages: messages,
      stream: true, // Streaming isteği
    }),
  });

  eventSource.onmessage = (event) => {
    const data = event.data;
    if (data === '[DONE]') {
      eventSource.close();
      return;
    }
    try {
      const parsedData = JSON.parse(data);
      const aiMessage = parsedData.choices[0]?.message?.content;
      if (aiMessage) {
        onMessage(aiMessage);
      }
    } catch (error) {
      onError(error);
    }
  };

  eventSource.onerror = (error) => {
    onError(error);
    eventSource.close();
  };

  return () => {
    eventSource.close();
  };
};

buradaki dökümantasyona göre bir düzenleme yap:
Creates a model response for the given chat conversation.

Request body
messages
array

Required
A list of messages comprising the conversation so far. Depending on the model you use, different message types (modalities) are supported, like text, images, and audio.


Show possible types
model
string

Required
ID of the model to use. See the model endpoint compatibility table for details on which models work with the Chat API.

store
boolean or null

Optional
Defaults to false
Whether or not to store the output of this chat completion request for use in our model distillation or evals products.

metadata
object or null

Optional
Developer-defined tags and values used for filtering completions in the dashboard.

frequency_penalty
number or null

Optional
Defaults to 0
Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.

See more information about frequency and presence penalties.

logit_bias
map

Optional
Defaults to null
Modify the likelihood of specified tokens appearing in the completion.

Accepts a JSON object that maps tokens (specified by their token ID in the tokenizer) to an associated bias value from -100 to 100. Mathematically, the bias is added to the logits generated by the model prior to sampling. The exact effect will vary per model, but values between -1 and 1 should decrease or increase likelihood of selection; values like -100 or 100 should result in a ban or exclusive selection of the relevant token.

logprobs
boolean or null

Optional
Defaults to false
Whether to return log probabilities of the output tokens or not. If true, returns the log probabilities of each output token returned in the content of message.

top_logprobs
integer or null

Optional
An integer between 0 and 20 specifying the number of most likely tokens to return at each token position, each with an associated log probability. logprobs must be set to true if this parameter is used.

max_tokens
Deprecated
integer or null

Optional
The maximum number of tokens that can be generated in the chat completion. This value can be used to control costs for text generated via API.

This value is now deprecated in favor of max_completion_tokens, and is not compatible with o1 series models.

max_completion_tokens
integer or null

Optional
An upper bound for the number of tokens that can be generated for a completion, including visible output tokens and reasoning tokens.

n
integer or null

Optional
Defaults to 1
How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the choices. Keep n as 1 to minimize costs.

presence_penalty
number or null

Optional
Defaults to 0
Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics.

See more information about frequency and presence penalties.

response_format
object

Optional
An object specifying the format that the model must output. Compatible with GPT-4o, GPT-4o mini, GPT-4 Turbo and all GPT-3.5 Turbo models newer than gpt-3.5-turbo-1106.

Setting to { "type": "json_schema", "json_schema": {...} } enables Structured Outputs which ensures the model will match your supplied JSON schema. Learn more in the Structured Outputs guide.

Setting to { "type": "json_object" } enables JSON mode, which ensures the message the model generates is valid JSON.

Important: when using JSON mode, you must also instruct the model to produce JSON yourself via a system or user message. Without this, the model may generate an unending stream of whitespace until the generation reaches the token limit, resulting in a long-running and seemingly "stuck" request. Also note that the message content may be partially cut off if finish_reason="length", which indicates the generation exceeded max_tokens or the conversation exceeded the max context length.


Show possible types
seed
integer or null

Optional
This feature is in Beta. If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same seed and parameters should return the same result. Determinism is not guaranteed, and you should refer to the system_fingerprint response parameter to monitor changes in the backend.

service_tier
string or null

Optional
Defaults to null
Specifies the latency tier to use for processing the request. This parameter is relevant for customers subscribed to the scale tier service:

If set to 'auto', and the Project is Scale tier enabled, the system will utilize scale tier credits until they are exhausted.
If set to 'auto', and the Project is not Scale tier enabled, the request will be processed using the default service tier with a lower uptime SLA and no latency guarentee.
If set to 'default', the request will be processed using the default service tier with a lower uptime SLA and no latency guarentee.
When not set, the default behavior is 'auto'.
When this parameter is set, the response body will include the service_tier utilized.

stop
string / array / null

Optional
Defaults to null
Up to 4 sequences where the API will stop generating further tokens.

stream
boolean or null

Optional
Defaults to false
If set, partial message deltas will be sent, like in ChatGPT. Tokens will be sent as data-only server-sent events as they become available, with the stream terminated by a data: [DONE] message. Example Python code.

stream_options
object or null

Optional
Defaults to null
Options for streaming response. Only set this when you set stream: true.


Show properties
temperature
number or null

Optional
Defaults to 1
What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.

We generally recommend altering this or top_p but not both.

top_p
number or null

Optional
Defaults to 1
An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered.

We generally recommend altering this or temperature but not both.

tools
array

Optional
A list of tools the model may call. Currently, only functions are supported as a tool. Use this to provide a list of functions the model may generate JSON inputs for. A max of 128 functions are supported.


Show properties
tool_choice
string or object

Optional
Controls which (if any) tool is called by the model. none means the model will not call any tool and instead generates a message. auto means the model can pick between generating a message or calling one or more tools. required means the model must call one or more tools. Specifying a particular tool via {"type": "function", "function": {"name": "my_function"}} forces the model to call that tool.

none is the default when no tools are present. auto is the default if tools are present.


Show possible types
parallel_tool_calls
boolean

Optional
Defaults to true
Whether to enable parallel function calling during tool use.

user
string

Optional
A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. Learn more.

function_call
Deprecated
string or object

Optional
Deprecated in favor of tool_choice.

Controls which (if any) function is called by the model. none means the model will not call a function and instead generates a message. auto means the model can pick between generating a message or calling a function. Specifying a particular function via {"name": "my_function"} forces the model to call that function.

none is the default when no functions are present. auto is the default if functions are present.


Show possible types
functions
Deprecated
array

Optional
Deprecated in favor of tools.

A list of functions the model may generate JSON inputs for.


Show properties
Returns
Returns a chat completion object, or a streamed sequence of chat completion chunk objects if the request is streamed.

Default
Image input
Streaming
Functions
Logprobs
Example request
gpt-4o

gpt-4o
curl

curl
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4o",
    "messages": [
      {
        "role": "system",
        "content": "You are a helpful assistant."
      },
      {
        "role": "user",
        "content": "Hello!"
      }
    ]
  }'
Response
{
  "id": "chatcmpl-123",
  "object": "chat.completion",
  "created": 1677652288,
  "model": "gpt-4o-mini",
  "system_fingerprint": "fp_44709d6fcb",
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": "\n\nHello there, how may I assist you today?",
    },
    "logprobs": null,
    "finish_reason": "stop"
  }],
  "usage": {
    "prompt_tokens": 9,
    "completion_tokens": 12,
    "total_tokens": 21,
    "completion_tokens_details": {
      "reasoning_tokens": 0
    }
  }
}
The chat completion object
Represents a chat completion response returned by model, based on the provided input.

id
string

A unique identifier for the chat completion.

choices
array

A list of chat completion choices. Can be more than one if n is greater than 1.


Show properties
created
integer

The Unix timestamp (in seconds) of when the chat completion was created.

model
string

The model used for the chat completion.

service_tier
string or null

The service tier used for processing the request. This field is only included if the service_tier parameter is specified in the request.

system_fingerprint
string

This fingerprint represents the backend configuration that the model runs with.

Can be used in conjunction with the seed request parameter to understand when backend changes have been made that might impact determinism.

object
string

The object type, which is always chat.completion.

usage
object

Usage statistics for the completion request.


Show properties
The chat completion object
{
  "id": "chatcmpl-123",
  "object": "chat.completion",
  "created": 1677652288,
  "model": "gpt-4o-mini",
  "system_fingerprint": "fp_44709d6fcb",
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": "\n\nHello there, how may I assist you today?",
    },
    "logprobs": null,
    "finish_reason": "stop"
  }],
  "usage": {
    "prompt_tokens": 9,
    "completion_tokens": 12,
    "total_tokens": 21,
    "completion_tokens_details": {
      "reasoning_tokens": 0
    }
  }
}
The chat completion chunk object
Represents a streamed chunk of a chat completion response returned by model, based on the provided input.

id
string

A unique identifier for the chat completion. Each chunk has the same ID.

choices
array

A list of chat completion choices. Can contain more than one elements if n is greater than 1. Can also be empty for the last chunk if you set stream_options: {"include_usage": true}.


Show properties
created
integer

The Unix timestamp (in seconds) of when the chat completion was created. Each chunk has the same timestamp.

model
string

The model to generate the completion.

service_tier
string or null

The service tier used for processing the request. This field is only included if the service_tier parameter is specified in the request.

system_fingerprint
string

This fingerprint represents the backend configuration that the model runs with. Can be used in conjunction with the seed request parameter to understand when backend changes have been made that might impact determinism.

object
string

The object type, which is always chat.completion.chunk.

usage
object

An optional field that will only be present when you set stream_options: {"include_usage": true} in your request. When present, it contains a null value except for the last chunk which contains the token usage statistics for the entire request.


Show properties

aynı zamanda şunu unutma bu api serverini kullanmaya devam edeceğiz:
  const OPENAI_ENDPOINT = 'https://text.pollinations.ai/openai';
bu endpoint olacak ve api key gerektirmiyor. openai alt yapısıyla kullanılabilir. uygun güncellemeleri yap.
// src/screens/ChatScreen.tsx
import React, { useState, useEffect, useRef } from 'react';
import { View, Text, FlatList, Image, TouchableOpacity, TextInput, StyleSheet, ActivityIndicator } from 'react-native';
import { useNavigation, useRoute } from '@react-navigation/native';
import LottieView from 'lottie-react-native';
import { HistoricalFigure, Message } from '../types/types';
import { fetchAIResponse, fetchAIResponseStream } from '../services/openaiService';
import { db } from '../services/firebaseConfig';
import { doc, getDoc, collection, addDoc } from 'firebase/firestore';
import uuid from 'react-native-uuid';
import MessageItem from '../components/MessageItem';
import AsyncStorage from '@react-native-async-storage/async-storage';

interface RouteParams {
  figure: HistoricalFigure;
}

const ChatScreen = () => {
  const navigation = useNavigation();
  const route = useRoute();
  const { figure } = route.params as RouteParams;
  const [messages, setMessages] = useState<Message[]>([]);
  const [inputText, setInputText] = useState<string>('');
  const [isTyping, setIsTyping] = useState<boolean>(false);
  const flatListRef = useRef<FlatList>(null);
  const aiMessageRef = useRef<Message | null>(null);

  useEffect(() => {
    const initializeChat = async () => {
      try {
        // Firestore'dan systemPrompt'u getir
        const figureDoc = doc(db,'figures', figure.id);
        const figureSnapshot = await getDoc(figureDoc);
        if (figureSnapshot.exists()) {
          const figureData = figureSnapshot.data() as HistoricalFigure;
          // Konuşmaya sistem mesajıyla başla
          const systemMessage: Message = {
            id: uuid.v4().toString(),
            text: figureData.systemPrompt,
            isUser: false,
          };
          setMessages([systemMessage]);

          // Mesajı Firestore ve AsyncStorage'a kaydet
          await saveMessage(systemMessage);
        } else {
          const errorMessage: Message = {
            id: uuid.v4().toString(),
            text: "Üzgünüm, bu karakter hakkında bilgi bulunamadı.",
            isUser: false,
          };
          setMessages([errorMessage]);

          // Hata mesajını Firestore ve AsyncStorage'a kaydet
          await saveMessage(errorMessage);
        }
      } catch (error) {
        console.debug('Error initializing chat:', error);
      }
    };

    // İlk başta konuşmayı yükle
    initializeChat();
  }, [figure.id]);

  const sendMessage = async () => {
    if (inputText.trim() === '') return;

    const userMessage: Message = {
      id: uuid.v4().toString(),
      text: inputText,
      isUser: true,
    };
    setMessages(prevMessages => [...prevMessages, userMessage]);
    setInputText('');
    setIsTyping(true);

    // Kullanıcı mesajını Firestore ve AsyncStorage'a kaydet
    await saveMessage(userMessage);

    // OpenAI API için mesajları hazırla
    const systemMessage = {
      role: 'system',
      content: figure.systemPrompt,
    };
    const userMessageAPI = {
      role: 'user',
      content: inputText,
    };
    const apiMessages = [systemMessage, userMessageAPI];

    try {
      // AI yanıtını streaming olarak al
      fetchAIResponseStream(apiMessages, (text: string) => {
        if (!aiMessageRef.current) {
          aiMessageRef.current = {
            id: uuid.v4().toString(),
            text: '',
            isUser: false,
          };
          setMessages(prevMessages => [...prevMessages, aiMessageRef.current!]);
        }

        aiMessageRef.current.text += text;
        setMessages(prevMessages =>
          prevMessages.map(msg => (msg.id === aiMessageRef.current!.id ? aiMessageRef.current! : msg))
        );

        // Altına kaydır
        flatListRef.current?.scrollToEnd({ animated: true });
      }, (error: any) => {
        console.debug('Streaming error:', error);
        setIsTyping(false);
      }).then(() => {
        // Streaming tamamlandığında
        setIsTyping(false);

        // AI mesajını Firestore ve AsyncStorage'a kaydet
        if (aiMessageRef.current) {
          saveMessage(aiMessageRef.current);
          aiMessageRef.current = null;
        }
      });
    } catch (error) {
      console.debug('Error sending message:', error);
      setIsTyping(false);
    }
  };

  const saveMessage = async (message: Message) => {
    try {
      // Firestore'a kaydet
      const messagesCollection = collection(db,'figures', figure.id, 'messages');
      await addDoc(messagesCollection, message);

      // AsyncStorage'a kaydet
      const storedMessages = await AsyncStorage.getItem(`messages_${figure.id}`);
      const parsedMessages: Message[] = storedMessages ? JSON.parse(storedMessages) : [];
      parsedMessages.push(message);
      await AsyncStorage.setItem(`messages_${figure.id}`, JSON.stringify(parsedMessages));
    } catch (error) {
      console.debug('Error saving message:', error);
    }
  };

  const loadMessages = async () => {
    try {
      const storedMessages = await AsyncStorage.getItem(`messages_${figure.id}`);
      if (storedMessages) {
        setMessages(JSON.parse(storedMessages));
      }
    } catch (error) {
      console.debug('Error loading messages:', error);
    }
  };

  useEffect(() => {
    loadMessages();
  }, []);

  const renderMessageItem = ({ item }: { item: Message }) => (
    <MessageItem message={item} />
  );

  return (
    <View style={styles.container}>
      {/* Header */}
      <View style={styles.header}>
        <TouchableOpacity onPress={() => navigation.goBack()}>
          <Text style={styles.backButton}>←</Text>
        </TouchableOpacity>
        <Image source={{ uri: figure.image }} style={styles.headerAvatar} />
        <Text style={styles.headerName}>{figure.name}</Text>
      </View>

      {/* Mesaj Listesi */}
      <FlatList
        ref={flatListRef}
        data={messages}
        renderItem={renderMessageItem}
        keyExtractor={(item) => item.id}
        style={styles.messageList}
        onContentSizeChange={() => flatListRef.current?.scrollToEnd({ animated: true })}
      />

      {/* Yazma Göstergesi */}
      {isTyping && (
        <View style={styles.typingIndicator}>
          <LottieView
            source={require('../../assets/typing-animation.json')}
            autoPlay
            loop
            style={styles.typingAnimation}
          />
        </View>
      )}

      {/* Giriş Alanı */}
      <View style={styles.inputContainer}>
        <TextInput
          style={styles.input}
          value={inputText}
          onChangeText={setInputText}
          placeholder="Mesajınızı yazın..."
          onSubmitEditing={sendMessage}
          returnKeyType="send"
        />
        <TouchableOpacity onPress={sendMessage} style={styles.sendButton}>
          <Text style={styles.sendButtonText}>Gönder</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
  header: {
    flexDirection: 'row',
    alignItems: 'center',
    padding: 15,
    borderBottomWidth: 1,
    borderBottomColor: '#e0e0e0',
  },
  backButton: {
    fontSize: 24,
    marginRight: 15,
  },
  headerAvatar: {
    width: 40,
    height: 40,
    borderRadius: 20,
    marginRight: 10,
  },
  headerName: {
    fontSize: 18,
    fontWeight: 'bold',
  },
  messageList: {
    flex: 1,
    padding: 15,
  },
  typingIndicator: {
    paddingLeft: 15,
    paddingBottom: 10,
  },
  typingAnimation: {
    width: 80,
    height: 40,
  },
  inputContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    padding: 10,
    borderTopWidth: 1,
    borderTopColor: '#e0e0e0',
  },
  input: {
    flex: 1,
    height: 40,
    borderRadius: 20,
    backgroundColor: '#f0f0f0',
    paddingHorizontal: 15,
    marginRight: 10,
  },
  sendButton: {
    backgroundColor: '#007AFF',
    borderRadius: 20,
    paddingVertical: 10,
    paddingHorizontal: 15,
  },
  sendButtonText: {
    color: '#fff',
    fontWeight: 'bold',
  },
});

export default ChatScreen;